cli,libnm: merge branch 'th/cli-team-cleanup'

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/merge_requests/121
This commit is contained in:
Thomas Haller 2019-04-25 09:32:20 +02:00
commit 5aff6fc83b
26 changed files with 2082 additions and 938 deletions

8
.gitignore vendored
View file

@ -63,9 +63,11 @@ test-*.trs
/clients/cli/nmcli
/clients/common/settings-docs.h
/clients/common/tests/test-general
/clients/common/tests/test-libnm-core-aux
/clients/nm-online
/clients/tui/newt/libnmt-newt.a
/clients/tui/nmtui
/clients/nm-online
/data/NetworkManager.service
/data/NetworkManager-wait-online.service
@ -146,8 +148,8 @@ test-*.trs
/examples/C/qt/list-connections
/examples/C/qt/change-ipv4-addresses
/shared/nm-version-macros.h
/shared/nm-utils/tests/test-shared-general
/shared/nm-version-macros.h
/introspection/org.freedesktop.NetworkManager*.[ch]
@ -278,8 +280,6 @@ test-*.trs
/src/tests/test-utils
/src/tests/test-wired-defname
/clients/common/tests/test-general
/vapi/*.vapi
# The following names are no longer present on this branch,

View file

@ -449,6 +449,8 @@ shared_nm_libnm_core_aux_libnm_libnm_core_aux_la_CPPFLAGS = \
shared_nm_libnm_core_aux_libnm_libnm_core_aux_la_SOURCES = \
shared/nm-libnm-core-aux/nm-dispatcher-api.h \
shared/nm-libnm-core-aux/nm-libnm-core-aux.c \
shared/nm-libnm-core-aux/nm-libnm-core-aux.h \
$(NULL)
shared_nm_libnm_core_aux_libnm_libnm_core_aux_la_LDFLAGS = \
@ -4101,6 +4103,8 @@ clients_common_tests_test_general_LDADD = \
$(clients_common_tests_test_general_OBJECTS): $(libnm_core_lib_h_pub_mkenums)
###############################################################################
EXTRA_DIST += \
clients/common/tests/wg-test0.conf \
clients/common/tests/wg-test1.conf \
@ -4108,6 +4112,40 @@ EXTRA_DIST += \
clients/common/tests/wg-test3.conf \
$(NULL)
###############################################################################
check_programs += clients/common/tests/test-libnm-core-aux
clients_common_tests_test_libnm_core_aux_CPPFLAGS = \
$(dflt_cppflags) \
-I$(builddir)/shared \
-I$(srcdir)/shared \
-I$(builddir)/libnm-core \
-I$(srcdir)/libnm-core \
-I$(builddir)/libnm \
-I$(srcdir)/libnm \
-DNETWORKMANAGER_COMPILATION_TEST \
-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_CLIENT \
$(CODE_COVERAGE_CFLAGS) \
$(GLIB_CFLAGS) \
$(SANITIZER_LIB_CFLAGS) \
$(NULL)
clients_common_tests_test_libnm_core_aux_LDFLAGS = \
$(CODE_COVERAGE_LDFLAGS) \
$(SANITIZER_EXEC_LDFLAGS) \
$(NULL)
clients_common_tests_test_libnm_core_aux_LDADD = \
shared/nm-libnm-core-aux/libnm-libnm-core-aux.la \
libnm/libnm.la \
shared/nm-glib-aux/libnm-glib-aux.la \
$(GLIB_LIBS) \
$(NULL)
$(clients_common_tests_test_libnm_core_aux_OBJECTS): $(libnm_core_lib_h_pub_mkenums)
$(clients_common_tests_test_libnm_core_aux_OBJECTS): $(libnm_lib_h_pub_mkenums)
###############################################################################
# clients/cli
###############################################################################

View file

@ -915,88 +915,6 @@ signal_handler (gpointer user_data)
return G_SOURCE_CONTINUE;
}
static void
nmc_convert_strv_to_string (const GValue *src_value, GValue *dest_value)
{
char **strings;
strings = g_value_get_boxed (src_value);
if (strings)
g_value_take_string (dest_value, g_strjoinv (",", strings));
else
g_value_set_string (dest_value, "");
}
static void
nmc_convert_string_hash_to_string (const GValue *src_value, GValue *dest_value)
{
GHashTable *hash;
GHashTableIter iter;
const char *key, *value;
GString *string;
hash = (GHashTable *) g_value_get_boxed (src_value);
string = g_string_new (NULL);
if (hash) {
g_hash_table_iter_init (&iter, hash);
while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value)) {
if (string->len)
g_string_append_c (string, ',');
g_string_append_printf (string, "%s=%s", key, value);
}
}
g_value_take_string (dest_value, g_string_free (string, FALSE));
}
static void
nmc_convert_bytes_to_string (const GValue *src_value, GValue *dest_value)
{
GBytes *bytes;
const guint8 *array;
gsize length;
GString *printable;
guint i = 0;
bytes = g_value_get_boxed (src_value);
printable = g_string_new ("[");
if (bytes) {
array = g_bytes_get_data (bytes, &length);
while (i < MIN (length, 35)) {
if (i > 0)
g_string_append_c (printable, ' ');
g_string_append_printf (printable, "0x%02X", array[i++]);
}
if (i < length)
g_string_append (printable, " ... ");
}
g_string_append_c (printable, ']');
g_value_take_string (dest_value, g_string_free (printable, FALSE));
}
static void
nmc_value_transforms_register (void)
{
g_value_register_transform_func (G_TYPE_STRV,
G_TYPE_STRING,
nmc_convert_strv_to_string);
/* This depends on the fact that all of the hash-table-valued properties
* in libnm-core are string->string.
*/
g_value_register_transform_func (G_TYPE_HASH_TABLE,
G_TYPE_STRING,
nmc_convert_string_hash_to_string);
g_value_register_transform_func (G_TYPE_BYTES,
G_TYPE_STRING,
nmc_convert_bytes_to_string);
}
void
nm_cli_spawn_pager (NmCli *nmc)
{
@ -1054,8 +972,6 @@ main (int argc, char *argv[])
/* Save terminal settings */
tcgetattr (STDIN_FILENO, &termios_orig);
nmc_value_transforms_register ();
nm_cli.return_text = g_string_new (_("Success"));
loop = g_main_loop_new (NULL, FALSE);

View file

@ -28,6 +28,7 @@
#include "nm-glib-aux/nm-enum-utils.h"
#include "nm-glib-aux/nm-secret-utils.h"
#include "nm-libnm-core-intern/nm-libnm-core-utils.h"
#include "nm-libnm-core-aux/nm-libnm-core-aux.h"
#include "nm-vpn-helpers.h"
#include "nm-client-utils.h"
@ -76,6 +77,25 @@ _gtype_property_get_gtype (GType gtype, const char *property_name)
/*****************************************************************************/
static char *
bytes_to_string (GBytes *bytes)
{
const guint8 *data;
gsize len;
if (!bytes)
return NULL;
data = g_bytes_get_data (bytes, &len);
return nm_utils_bin2hexstr_full (data,
len,
'\0',
TRUE,
NULL);
}
/*****************************************************************************/
static int
_int64_cmp_desc (gconstpointer a,
gconstpointer b,
@ -432,158 +452,7 @@ _parse_ip_route (int family,
return route;
}
static char *
_dump_team_link_watcher (NMTeamLinkWatcher *watcher)
{
const char *name;
NMTeamLinkWatcherArpPingFlags flags;
GString *w_dump;
if (!watcher)
return NULL;
w_dump = g_string_new (NULL);
name = nm_team_link_watcher_get_name (watcher);
g_string_append_printf (w_dump, "name=%s", name);
#define DUMP_WATCHER_INT(str, watcher, name, key) \
G_STMT_START { \
int _val = nm_team_link_watcher_get_##key (watcher); \
\
if (_val) \
g_string_append_printf (str, " %s=%d", name, _val); \
} G_STMT_END;
if (nm_streq (name, NM_TEAM_LINK_WATCHER_ETHTOOL)) {
DUMP_WATCHER_INT (w_dump, watcher, "delay-up", delay_up);
DUMP_WATCHER_INT (w_dump, watcher, "delay-down", delay_down);
return g_string_free (w_dump, FALSE);
}
/* NM_TEAM_LINK_WATCHER_NSNA_PING and NM_TEAM_LINK_WATCHER_ARP_PING */
DUMP_WATCHER_INT (w_dump, watcher, "init-wait", init_wait);
DUMP_WATCHER_INT (w_dump, watcher, "interval", interval);
DUMP_WATCHER_INT (w_dump, watcher, "missed-max", missed_max);
g_string_append_printf (w_dump, " target-host=%s",
nm_team_link_watcher_get_target_host (watcher));
if (nm_streq (name, NM_TEAM_LINK_WATCHER_NSNA_PING))
return g_string_free (w_dump, FALSE);
DUMP_WATCHER_INT (w_dump, watcher, "vlanid", vlanid);
#undef DUMP_WATCHER_INT
g_string_append_printf (w_dump, " source-host=%s",
nm_team_link_watcher_get_source_host (watcher));
flags = nm_team_link_watcher_get_flags (watcher);
if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE)
g_string_append_printf (w_dump, " validate-active=true");
if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE)
g_string_append_printf (w_dump, " validate-inactive=true");
if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS)
g_string_append_printf (w_dump, "send-always=true");
return g_string_free (w_dump, FALSE);
}
static NMTeamLinkWatcher *
_parse_team_link_watcher (const char *str,
GError **error)
{
gs_free const char **watcherv = 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;
gs_free const char *target_host = NULL;
gs_free const char *source_host = NULL;
NMTeamLinkWatcherArpPingFlags flags = 0;
nm_assert (str);
nm_assert (!error || !*error);
str_clean = nm_strstrip_avoid_copy_a (300, str, &str_clean_free);
watcherv = nm_utils_strsplit_set (str_clean, " \t");
if (!watcherv) {
g_set_error (error, 1, 0, "'%s' is not valid", str);
return NULL;
}
for (i = 0; watcherv[i]; i++) {
gs_free const char **pair = NULL;
pair = nm_utils_strsplit_set (watcherv[i], "=");
if (!pair) {
g_set_error (error, 1, 0, "'%s' is not valid: %s", watcherv[i],
"properties should be specified as 'key=value'");
return NULL;
}
if (!pair[1]) {
g_set_error (error, 1, 0, "'%s' is not valid: %s", watcherv[i],
"missing key value");
return NULL;
}
if (pair[2]) {
g_set_error (error, 1, 0, "'%s' is not valid: %s", watcherv[i],
"properties should be specified as 'key=value'");
return NULL;
}
if (nm_streq (pair[0], "name"))
name = g_strdup (pair[1]);
else if ( nm_streq (pair[0], "delay-up")
|| nm_streq (pair[0], "init-wait"))
val1 = _nm_utils_ascii_str_to_int64 (pair[1], 10, 0, G_MAXINT32, -1);
else if ( nm_streq (pair[0], "delay-down")
|| nm_streq (pair[0], "interval"))
val2 = _nm_utils_ascii_str_to_int64 (pair[1], 10, 0, G_MAXINT32, -1);
else if (nm_streq (pair[0], "missed-max"))
val3 = _nm_utils_ascii_str_to_int64 (pair[1], 10, 0, G_MAXINT32, -1);
else if (nm_streq (pair[0], "vlanid"))
val4 = _nm_utils_ascii_str_to_int64 (pair[1], 10, -1, 4094, -2);
else if (nm_streq (pair[0], "target-host"))
target_host = g_strdup (pair[1]);
else if (nm_streq (pair[0], "source-host"))
source_host = g_strdup (pair[1]);
else if (nm_streq (pair[0], "validate-active")) {
if (nm_streq (pair[1], "true"))
flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE;
} else if (nm_streq (pair[0], "validate-inactive")) {
if (nm_streq (pair[1], "true"))
flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE;
} else if (nm_streq (pair[0], "send-always")) {
if (nm_streq (pair[1], "true"))
flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS;
} else {
g_set_error (error, 1, 0, "'%s' is not valid: %s", watcherv[i],
"unknown key");
return NULL;
}
if ((val1 < 0) || (val2 < 0) || (val3 < 0)) {
g_set_error (error, 1, 0, "'%s' is not valid: %s", watcherv[i],
"value is not a valid number [0, MAXINT]");
return NULL;
}
if (val4 < -1) {
g_set_error (error, 1, 0, "'%s' is not valid: %s", watcherv[i],
"value is not a valid number [-1, 4094]");
return NULL;
}
}
if (nm_streq0 (name, NM_TEAM_LINK_WATCHER_ETHTOOL))
return nm_team_link_watcher_new_ethtool (val1, val2, error);
else if (nm_streq0 (name, NM_TEAM_LINK_WATCHER_NSNA_PING))
return nm_team_link_watcher_new_nsna_ping (val1, val2, val3, target_host, error);
else if (nm_streq0 (name, NM_TEAM_LINK_WATCHER_ARP_PING))
return nm_team_link_watcher_new_arp_ping2 (val1, val2, val3, val4, target_host, source_host, flags, error);
if (!name)
g_set_error (error, 1, 0, "link watcher name missing");
else
g_set_error (error, 1, 0, "unknown link watcher name: '%s'", name);
return NULL;
}
/*****************************************************************************/
/* Max priority values from libnm-core/nm-setting-vlan.c */
#define MAX_SKB_PRIO G_MAXUINT32
@ -849,9 +718,21 @@ _SET_FCN_DO_REMOVE (char modifier, const char *value)
#define RETURN_STR_TO_FREE(val) \
G_STMT_START { \
char *_val = (val); \
\
return ((*(out_to_free)) = _val); \
} G_STMT_END
#define RETURN_STR_TEMPORARY(val) \
G_STMT_START { \
const char *_val = (val); \
\
if (_val == NULL) \
return NULL; \
if (_val[0] == '\0') \
return ""; \
return ((*(out_to_free)) = g_strdup (_val)); \
} G_STMT_END
static gboolean
_gobject_property_is_default (NMSetting *setting, const char *prop_name)
{
@ -905,73 +786,167 @@ _gobject_property_reset_default (NMSetting *setting, const char *prop_name)
return _gobject_property_reset (setting, prop_name, TRUE);
}
static const char *
_coerce_str_emptyunset (NMMetaAccessorGetType get_type,
gboolean is_default,
const char *cstr,
char **out_str)
{
nm_assert (out_str && !*out_str);
nm_assert ( (!is_default && cstr && cstr[0] != '\0')
|| NM_IN_STRSET (cstr, NULL, ""));
if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) {
if ( !cstr
|| cstr[0] == '\0') {
if (is_default)
return "";
else
return "\"\"";
}
nm_assert (!is_default);
return (*out_str = g_strdup_printf ("\"%s\"", cstr));
}
/* we coerce NULL/"" to either "" or " ". */
if ( !cstr
|| cstr[0] == '\0') {
if (is_default)
return "";
else
return " ";
}
nm_assert (!is_default);
return cstr;
}
static gboolean
_is_default (const NMMetaPropertyInfo *property_info,
NMSetting *setting)
{
if ( property_info->property_typ_data
&& property_info->property_typ_data->is_default_fcn)
return !!(property_info->property_typ_data->is_default_fcn (setting));
return _gobject_property_is_default (setting, property_info->property_name);
}
static gconstpointer
_get_fcn_gobject_impl (const NMMetaPropertyInfo *property_info,
NMSetting *setting,
NMMetaAccessorGetType get_type,
gboolean handle_emptyunset,
gboolean *out_is_default,
gpointer *out_to_free)
{
const char *cstr;
GType gtype_prop;
nm_auto_unset_gvalue GValue val = G_VALUE_INIT;
gboolean is_default;
gboolean glib_handles_str_transform;
RETURN_UNSUPPORTED_GET_TYPE ();
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 "";
}
is_default = _is_default (property_info, setting);
NM_SET_OUT (out_is_default, is_default);
gtype_prop = _gobject_property_get_gtype (G_OBJECT (setting), property_info->property_name);
glib_handles_str_transform = !NM_IN_SET (gtype_prop, G_TYPE_BOOLEAN,
G_TYPE_STRV,
G_TYPE_BYTES,
G_TYPE_HASH_TABLE);
if (glib_handles_str_transform) {
/* We rely on the type convertion of the gobject property to string. */
g_value_init (&val, G_TYPE_STRING);
} else
g_value_init (&val, gtype_prop);
g_object_get_property (G_OBJECT (setting), property_info->property_name, &val);
/* Currently only one particular property asks us to "handle_emptyunset".
* So, don't implement it (yet) for the other types, where it's unneeded. */
nm_assert ( !handle_emptyunset
|| ( gtype_prop == G_TYPE_STRV
&& !glib_handles_str_transform));
if (glib_handles_str_transform)
RETURN_STR_TEMPORARY (g_value_get_string (&val));
if (gtype_prop == G_TYPE_BOOLEAN) {
gboolean b;
g_value_init (&val, gtype_prop);
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)
cstr = b ? _("yes") : _("no");
else
cstr = b ? "yes" : "no";
return cstr;
} else {
}
if (gtype_prop == G_TYPE_STRV) {
const char *const*strv;
strv = g_value_get_boxed (&val);
if (strv && strv[0])
RETURN_STR_TO_FREE (g_strjoinv (",", (char **) strv));
/* special hack for handling properties that can be empty and unset
* (see multilist.clear_emptyunset_fcn). */
if (handle_emptyunset) {
char *str = NULL;
cstr = _coerce_str_emptyunset (get_type, is_default, NULL, &str);
if (str)
RETURN_STR_TO_FREE (str);
RETURN_STR_TEMPORARY (cstr);
}
return "";
}
if (gtype_prop == G_TYPE_BYTES) {
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);
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;
str = bytes_to_string (g_value_get_boxed (&val));
NM_SET_OUT (out_is_default, !str || !str[0]);
RETURN_STR_TO_FREE (str);
}
if (gtype_prop == G_TYPE_HASH_TABLE) {
GHashTable *strdict;
gs_free const char **keys = NULL;
GString *str;
gsize i;
strdict = g_value_get_boxed (&val);
keys = nm_utils_strdict_get_keys (strdict, TRUE, NULL);
if (!keys)
return NULL;
str = g_string_new (NULL);
for (i = 0; keys[i]; i++) {
if (str->len > 0)
g_string_append_c (str, ',');
g_string_append_printf (str,
"%s=%s",
keys[i],
(const char *) g_hash_table_lookup (strdict, keys[i]));
}
RETURN_STR_TO_FREE (g_string_free (str, FALSE));
}
nm_assert_not_reached ();
return NULL;
}
static gconstpointer
_get_fcn_gobject (ARGS_GET_FCN)
{
return _get_fcn_gobject_impl (property_info, setting, get_type, out_is_default, out_to_free);
return _get_fcn_gobject_impl (property_info, setting, get_type, FALSE, out_is_default, out_to_free);
}
static gconstpointer
@ -1063,7 +1038,7 @@ _get_fcn_gobject_mtu (ARGS_GET_FCN)
if ( !property_info->property_typ_data
|| !property_info->property_typ_data->subtype.mtu.get_fcn)
return _get_fcn_gobject_impl (property_info, setting, get_type, out_is_default, out_to_free);
return _get_fcn_gobject_impl (property_info, setting, get_type, FALSE, out_is_default, out_to_free);
mtu = property_info->property_typ_data->subtype.mtu.get_fcn (setting);
if (mtu == 0) {
@ -1722,23 +1697,6 @@ wep_key_type_to_string (NMWepKeyType type)
}
}
static char *
bytes_to_string (GBytes *bytes)
{
const guint8 *data;
gsize len;
if (!bytes)
return NULL;
data = g_bytes_get_data (bytes, &len);
return nm_utils_bin2hexstr_full (data,
len,
'\0',
TRUE,
NULL);
}
static char *
vlan_flags_to_string (guint32 flags, NMMetaAccessorGetType get_type)
{
@ -1839,19 +1797,41 @@ _multilist_do_validate (const NMMetaPropertyInfo *property_info,
return item;
}
static gconstpointer
_get_fcn_multilist (ARGS_GET_FCN)
{
return _get_fcn_gobject_impl (property_info,
setting,
get_type,
property_info->property_typ_data->subtype.multilist.clear_emptyunset_fcn != NULL,
out_is_default,
out_to_free);
}
static gboolean
_multilist_clear_property (const NMMetaPropertyInfo *property_info,
NMSetting *setting,
gboolean is_set /* or else set default */)
{
if (property_info->property_typ_data->subtype.multilist.clear_emptyunset_fcn) {
property_info->property_typ_data->subtype.multilist.clear_emptyunset_fcn (setting, is_set);
return TRUE;
}
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);
}
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_RESET_DEFAULT_WITH_SUPPORTS_REMOVE (property_info, modifier, value))
return _multilist_clear_property (property_info, setting, FALSE);
if ( _SET_FCN_DO_REMOVE (modifier, value)
&& ( property_info->property_typ_data->subtype.multilist.remove_by_idx_fcn_u32
@ -1884,6 +1864,11 @@ _set_fcn_multilist (ARGS_SET_FCN)
}
}
if ( _SET_FCN_DO_SET_ALL (modifier, value)
&& property_info->property_typ_data->subtype.multilist.clear_emptyunset_fcn
&& value[0] == '\0')
return _multilist_clear_property (property_info, setting, FALSE);
strv = _value_strsplit (value,
property_info->property_typ_data->subtype.multilist.strsplit_plain
? VALUE_STRSPLIT_MODE_MULTILIST
@ -1906,11 +1891,13 @@ _set_fcn_multilist (ARGS_SET_FCN)
}
nstrv = j;
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);
if (_SET_FCN_DO_SET_ALL (modifier, value))
_multilist_clear_property (property_info, setting, TRUE);
else if ( property_info->property_typ_data->subtype.multilist.clear_emptyunset_fcn
&& _is_default (property_info, setting)) {
/* the property is already the default. But we hav here a '+' / '-' modifier, so
* that always makes it non-default (empty) first. */
_multilist_clear_property (property_info, setting, TRUE);
}
for (i = 0; i < nstrv; i++) {
@ -2298,21 +2285,6 @@ _set_fcn_cert_8021x (ARGS_SET_FCN)
}
}
static gconstpointer
_get_fcn_gobject_bytes (ARGS_GET_FCN)
{
gs_unref_bytes GBytes *bytes = NULL;
char *str;
RETURN_UNSUPPORTED_GET_TYPE ();
g_object_get (setting, property_info->property_name, &bytes, NULL);
str = bytes_to_string (bytes);
NM_SET_OUT (out_is_default, !str || !str[0]);
RETURN_STR_TO_FREE (str);
}
static gconstpointer
_get_fcn_bond_options (ARGS_GET_FCN)
{
@ -3362,8 +3334,7 @@ _objlist_set_fcn_ip_config_routes (NMSetting *setting,
static gboolean
_is_default_func_ip_config_dns_options (NMSetting *setting)
{
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));
return !nm_setting_ip_config_has_dns_options (NM_SETTING_IP_CONFIG (setting));
}
static void
@ -3779,9 +3750,9 @@ _objlist_obj_to_str_fcn_team_link_watchers (NMMetaAccessorGetType get_type,
else
watcher = nm_setting_team_port_get_link_watcher (NM_SETTING_TEAM_PORT (setting), idx);
s = _dump_team_link_watcher (watcher);
s = nm_utils_team_link_watcher_to_string (watcher);
if (s)
g_string_append (str, s);
nm_utils_escaped_tokens_escape_gstr (s, ESCAPED_TOKENS_DELIMITERS, str);
}
static gboolean
@ -3792,7 +3763,7 @@ _objlist_set_fcn_team_link_watchers (NMSetting *setting,
{
nm_auto_unref_team_link_watcher NMTeamLinkWatcher *watcher = NULL;
watcher = _parse_team_link_watcher (value, error);
watcher = nm_utils_team_link_watcher_from_string (value, error);
if (!watcher)
return FALSE;
if (NM_IS_SETTING_TEAM (setting)) {
@ -4412,7 +4383,7 @@ static const NMMetaPropertyType _pt_gobject_mtu = {
};
static const NMMetaPropertyType _pt_gobject_bytes = {
.get_fcn = _get_fcn_gobject_bytes,
.get_fcn = _get_fcn_gobject,
.set_fcn = _set_fcn_gobject_bytes,
};
@ -4466,7 +4437,7 @@ static const NMMetaPropertyType _pt_ethtool = {
};
static const NMMetaPropertyType _pt_multilist = {
.get_fcn = _get_fcn_gobject,
.get_fcn = _get_fcn_multilist,
.set_fcn = _set_fcn_multilist,
.set_supports_remove = TRUE,
};
@ -4485,6 +4456,7 @@ static const NMMetaPropertyType _pt_objlist = {
#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 MULTILIST_CLEAR_EMPTYUNSET_FCN(type, func) (((func) == ((void (*) (type *, gboolean )) (func))) ? ((void (*) (NMSetting *, gboolean )) (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)
@ -5595,6 +5567,7 @@ static const NMMetaPropertyInfo *const property_infos_IP4_CONFIG[] = {
.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),
.clear_emptyunset_fcn = MULTILIST_CLEAR_EMPTYUNSET_FCN (NMSettingIPConfig, nm_setting_ip_config_clear_dns_options),
.strsplit_plain = TRUE,
),
.is_default_fcn = _is_default_func_ip_config_dns_options,
@ -5807,6 +5780,7 @@ static const NMMetaPropertyInfo *const property_infos_IP6_CONFIG[] = {
.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),
.clear_emptyunset_fcn = MULTILIST_CLEAR_EMPTYUNSET_FCN (NMSettingIPConfig, nm_setting_ip_config_clear_dns_options),
.strsplit_plain = TRUE,
),
.is_default_fcn = _is_default_func_ip_config_dns_options,
@ -6662,7 +6636,6 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = {
.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),
.strsplit_plain = TRUE,
),
),
),
@ -6739,7 +6712,6 @@ static const NMMetaPropertyInfo *const property_infos_TEAM_PORT[] = {
.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),
.strsplit_plain = TRUE,
),
),
),

View file

@ -270,6 +270,13 @@ struct _NMMetaPropertyTypData {
guint32 (*get_num_fcn_u32) (NMSetting *setting);
guint (*get_num_fcn_u) (NMSetting *setting);
void (*clear_all_fcn) (NMSetting *setting);
/* some multilist properties distinguish between an empty list and
* and unset. If this function pointer is set, certain behaviors come
* into action to handle that. */
void (*clear_emptyunset_fcn) (NMSetting *setting,
gboolean is_set /* or else set default */);
gboolean (*add_fcn) (NMSetting *setting,
const char *item);
void (*add2_fcn) (NMSetting *setting,

View file

@ -1,23 +1,42 @@
test_unit = 'test-general'
deps = [
libnm_dep,
libnmc_dep,
libnmc_base_dep,
libnm_core_dep,
]
exe = executable(
'clients-' + test_unit,
test_unit + '.c',
dependencies: deps,
'clients-test-general',
'test-general.c',
dependencies: [
libnm_dep,
libnmc_dep,
libnmc_base_dep,
libnm_core_dep,
],
c_args: clients_cflags + [
'-DNETWORKMANAGER_COMPILATION_TEST',
],
)
test(
'clients/' + test_unit,
'clients/common/tests/test-general',
test_script,
args: test_args + [exe.full_path()],
)
###############################################################################
exe = executable(
'test-libnm-core-aux',
[ 'test-libnm-core-aux.c', ],
c_args: [
'-DNETWORKMANAGER_COMPILATION_TEST',
'-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_CLIENT',
],
dependencies: [
libnm_dep,
shared_nm_libnm_core_aux_dep,
shared_nm_libnm_core_intern_dep,
],
)
test(
'clients/common/tests/test-libnm-core-aux',
test_script,
args: test_args + [exe.full_path()]
)

View file

@ -0,0 +1,250 @@
/*
* 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.
*
* Copyright 2019 Red Hat, Inc.
*/
#include "nm-default.h"
#include "nm-libnm-core-aux/nm-libnm-core-aux.h"
#include "nm-libnm-core-intern/nm-libnm-core-utils.h"
#include "nm-utils/nm-test-utils.h"
/*****************************************************************************/
static NMTeamLinkWatcher *
_team_link_watcher_from_string_impl (const char *str, gsize nextra, const char *const*vextra)
{
NMTeamLinkWatcher *watcher;
gs_free char *str1_free = NULL;
gs_free_error GError *error = NULL;
gsize i;
g_assert (str);
watcher = nm_utils_team_link_watcher_from_string (str, &error);
nmtst_assert_success (watcher, error);
for (i = 0; i < 1 + nextra; i++) {
nm_auto_unref_team_link_watcher NMTeamLinkWatcher *watcher1 = NULL;
const char *str1;
if (i == 0) {
str1_free = nm_utils_team_link_watcher_to_string (watcher);
g_assert (str1_free);
str1 = str1_free;
g_assert_cmpstr (str, ==, str1);
} else
str1 = vextra[i - 1];
watcher1 = nm_utils_team_link_watcher_from_string (str1, &error);
nmtst_assert_success (watcher1, error);
if (!nm_team_link_watcher_equal (watcher, watcher1)) {
gs_free char *ss1 = NULL;
gs_free char *ss2 = NULL;
g_print (">>> watcher differs: \"%s\" vs. \"%s\"",
(ss1 = nm_utils_team_link_watcher_to_string (watcher)),
(ss2 = nm_utils_team_link_watcher_to_string (watcher1)));
g_print (">>> ORIG: \"%s\" vs. \"%s\"", str, str1);
g_assert_not_reached ();
}
g_assert (nm_team_link_watcher_equal (watcher1, watcher));
}
return watcher;
}
#define _team_link_watcher_from_string(str, ...) \
_team_link_watcher_from_string_impl ((str), NM_NARG (__VA_ARGS__), NM_MAKE_STRV (__VA_ARGS__))
/*****************************************************************************/
static void
test_team_link_watcher_tofro_string (void)
{
nm_auto_unref_team_link_watcher NMTeamLinkWatcher *w = NULL;
#define _team_link_watcher_cmp(watcher, \
name, \
delay_down, \
delay_up, \
init_wait, \
interval, \
missed_max, \
target_host, \
source_host, \
vlanid, \
arping_flags) \
G_STMT_START { \
nm_auto_unref_team_link_watcher NMTeamLinkWatcher *_w = g_steal_pointer (watcher); \
\
g_assert_cmpstr ((name), ==, nm_team_link_watcher_get_name (_w)); \
g_assert_cmpint ((delay_down), ==, nm_team_link_watcher_get_delay_down (_w)); \
g_assert_cmpint ((delay_up), ==, nm_team_link_watcher_get_delay_up (_w)); \
g_assert_cmpint ((init_wait), ==, nm_team_link_watcher_get_init_wait (_w)); \
g_assert_cmpint ((interval), ==, nm_team_link_watcher_get_interval (_w)); \
g_assert_cmpint ((missed_max), ==, nm_team_link_watcher_get_missed_max (_w)); \
g_assert_cmpstr ((target_host), ==, nm_team_link_watcher_get_target_host (_w)); \
g_assert_cmpstr ((source_host), ==, nm_team_link_watcher_get_source_host (_w)); \
g_assert_cmpint ((vlanid), ==, nm_team_link_watcher_get_vlanid (_w)); \
g_assert_cmpint ((arping_flags), ==, nm_team_link_watcher_get_flags (_w)); \
} G_STMT_END
w = _team_link_watcher_from_string ("name=ethtool",
"delay-up=0 name=ethtool",
" delay-down=0 name=ethtool ");
_team_link_watcher_cmp (&w,
"ethtool",
0,
0,
-1,
-1,
-1,
NULL,
NULL,
-1,
NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE);
w = _team_link_watcher_from_string ("name=ethtool delay-up=10",
" delay-down=0 delay-up=10 name=ethtool");
_team_link_watcher_cmp (&w,
"ethtool",
0,
10,
-1,
-1,
-1,
NULL,
NULL,
-1,
NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE);
w = _team_link_watcher_from_string ("name=ethtool delay-up=10 delay-down=11",
" delay-down=11 delay-up=10 name=ethtool");
_team_link_watcher_cmp (&w,
"ethtool",
11,
10,
-1,
-1,
-1,
NULL,
NULL,
-1,
NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE);
w = _team_link_watcher_from_string ("name=nsna_ping target-host=xxx",
"name=nsna_ping target-host=xxx",
" missed-max=3 target-host=xxx name=nsna_ping ");
_team_link_watcher_cmp (&w,
"nsna_ping",
-1,
-1,
0,
0,
3,
"xxx",
NULL,
-1,
NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE);
w = _team_link_watcher_from_string ("name=arp_ping target-host=xxx source-host=yzd",
" source-host=yzd target-host=xxx name=arp_ping ");
_team_link_watcher_cmp (&w,
"arp_ping",
-1,
-1,
0,
0,
3,
"xxx",
"yzd",
-1,
NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE);
w = _team_link_watcher_from_string ("name=arp_ping missed-max=0 target-host=xxx vlanid=0 source-host=yzd");
_team_link_watcher_cmp (&w,
"arp_ping",
-1,
-1,
0,
0,
0,
"xxx",
"yzd",
0,
NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE);
w = _team_link_watcher_from_string ("name=arp_ping target-host=xxx source-host=yzd validate-active=true",
"source-host=yzd send-always=false name=arp_ping validate-active=true validate-inactive=false target-host=xxx",
" source-host=yzd target-host=xxx validate-active=true name=arp_ping ");
_team_link_watcher_cmp (&w,
"arp_ping",
-1,
-1,
0,
0,
3,
"xxx",
"yzd",
-1,
NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE);
w = _team_link_watcher_from_string ("name=arp_ping target-host=xxx source-host=yzd validate-active=true validate-inactive=true send-always=true",
"source-host=yzd send-always=true name=arp_ping validate-active=true validate-inactive=true target-host=xxx",
"source-host=yzd send-always=true name=arp_ping validate-active=1 validate-inactive=yes target-host=xxx",
" source-host=yzd target-host=xxx validate-inactive=true send-always=true validate-active=true name=arp_ping ");
_team_link_watcher_cmp (&w,
"arp_ping",
-1,
-1,
0,
0,
3,
"xxx",
"yzd",
-1,
NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE
| NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE
| NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS);
w = _team_link_watcher_from_string ("name=arp_ping missed-max=0 target-host=xxx vlanid=0 source-host=yzd");
_team_link_watcher_cmp (&w,
"arp_ping",
-1,
-1,
0,
0,
0,
"xxx",
"yzd",
0,
NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE);
}
/*****************************************************************************/
NMTST_DEFINE ();
int main (int argc, char **argv)
{
nmtst_init (&argc, &argv, TRUE);
g_test_add_func ("/libnm-core-aux/test_team_link_watcher_tofro_string", test_team_link_watcher_tofro_string);
return g_test_run ();
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -889,7 +889,7 @@ class TestNmcli(NmTestBase):
replace_stdout.append((Util.memoize_nullary(lambda: self.srv.findConnectionUuid('con-gsm1')), 'UUID-con-gsm1-REPLACED-REPLACED-REPL'))
self.call_nmcli(['connection', 'add', 'type', 'gsm', 'autoconnect', 'no', 'con-name', 'con-gsm1', 'ifname', '*', 'apn', 'xyz.con-gsm1', 'serial.baud', '5', 'serial.send-delay', '100', 'serial.pari', '1'],
self.call_nmcli(['connection', 'add', 'type', 'gsm', 'autoconnect', 'no', 'con-name', 'con-gsm1', 'ifname', '*', 'apn', 'xyz.con-gsm1', 'serial.baud', '5', 'serial.send-delay', '100', 'serial.pari', '1', 'ipv4.dns-options', ' '],
replace_stdout = replace_stdout)
replace_stdout.append((Util.memoize_nullary(lambda: self.srv.findConnectionUuid('ethernet')), 'UUID-ethernet-REPLACED-REPLACED-REPL'))

View file

@ -256,7 +256,7 @@ libnm_core_dep = declare_dependency(
shared_nm_libnm_core_aux = static_library(
'nm-libnm-core-aux',
sources: files('../shared/nm-libnm-core-aux/nm-dispatcher-api.h'),
sources: files('../shared/nm-libnm-core-aux/nm-libnm-core-aux.c'),
c_args: [
'-DG_LOG_DOMAIN="@0@"'.format(libnm_name),
'-DNETWORKMANAGER_COMPILATION=(NM_NETWORKMANAGER_COMPILATION_WITH_GLIB|NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_LIB)',
@ -270,6 +270,7 @@ shared_nm_libnm_core_aux = static_library(
glib_dep,
shared_c_siphash_dep,
shared_nm_glib_aux_dep,
libnm_core_dep,
],
)

View file

@ -260,6 +260,8 @@ typedef gpointer (*NMUtilsCopyFunc) (gpointer);
const char **_nm_ip_address_get_attribute_names (const NMIPAddress *addr, gboolean sorted, guint *out_length);
void _nm_setting_wired_clear_s390_options (NMSettingWired *setting);
gboolean _nm_ip_route_attribute_validate_all (const NMIPRoute *route);
const char **_nm_ip_route_get_attribute_names (const NMIPRoute *route, gboolean sorted, guint *out_length);
GHashTable *_nm_ip_route_get_attributes (NMIPRoute *route);

View file

@ -994,6 +994,11 @@ read_hash_of_string (GKeyFile *file, NMSetting *setting, const char *key)
gboolean is_vpn;
gsize n_keys;
nm_assert ( (NM_IS_SETTING_VPN (setting) && nm_streq (key, NM_SETTING_VPN_DATA))
|| (NM_IS_SETTING_VPN (setting) && nm_streq (key, NM_SETTING_VPN_SECRETS))
|| (NM_IS_SETTING_BOND (setting) && nm_streq (key, NM_SETTING_BOND_OPTIONS))
|| (NM_IS_SETTING_USER (setting) && nm_streq (key, NM_SETTING_USER_DATA)));
keys = nm_keyfile_plugin_kf_get_keys (file, setting_name, &n_keys, NULL);
if (n_keys == 0)
return;
@ -1041,7 +1046,10 @@ read_hash_of_string (GKeyFile *file, NMSetting *setting, const char *key)
value);
}
g_object_set (setting, NM_SETTING_USER_DATA, data, NULL);
return;
}
nm_assert_not_reached ();
}
static gsize
@ -2019,6 +2027,64 @@ bridge_vlan_writer (KeyfileWriterInfo *info,
g_string_free (string, TRUE);
}
#define ETHERNET_S390_OPTIONS_GROUP_NAME "ethernet-s390-options"
static void
wired_s390_options_parser_full (KeyfileReaderInfo *info,
const NMMetaSettingInfo *setting_info,
const NMSettInfoProperty *property_info,
const ParseInfoProperty *pip,
NMSetting *setting)
{
NMSettingWired *s_wired = NM_SETTING_WIRED (setting);
gs_strfreev char **keys = NULL;
gsize n_keys;
gsize i;
keys = nm_keyfile_plugin_kf_get_keys (info->keyfile, ETHERNET_S390_OPTIONS_GROUP_NAME, &n_keys, NULL);
for (i = 0; i < n_keys; i++) {
gs_free char *value = NULL;
gs_free char *key_to_free = NULL;
value = nm_keyfile_plugin_kf_get_string (info->keyfile,
ETHERNET_S390_OPTIONS_GROUP_NAME,
keys[i],
NULL);
if (!value)
continue;
nm_setting_wired_add_s390_option (s_wired,
nm_keyfile_key_decode (keys[i],
&key_to_free),
value);
}
}
static void
wired_s390_options_writer_full (KeyfileWriterInfo *info,
const NMMetaSettingInfo *setting_info,
const NMSettInfoProperty *property_info,
const ParseInfoProperty *pip,
NMSetting *setting)
{
NMSettingWired *s_wired = NM_SETTING_WIRED (setting);
guint i, n;
n = nm_setting_wired_get_num_s390_options (s_wired);
for (i = 0; i < n; i++) {
const char *opt_key;
const char *opt_val;
gs_free char *key_to_free = NULL;
nm_setting_wired_get_s390_option (s_wired, i, &opt_key, &opt_val);
nm_keyfile_plugin_kf_set_string (info->keyfile,
ETHERNET_S390_OPTIONS_GROUP_NAME,
nm_keyfile_key_encode (opt_key, &key_to_free),
opt_val);
}
}
static void
ip_routing_rule_writer_full (KeyfileWriterInfo *info,
const NMMetaSettingInfo *setting_info,
@ -2131,6 +2197,11 @@ write_hash_of_string (GKeyFile *file,
gs_free const char **keys = NULL;
guint i, l;
nm_assert ( (NM_IS_SETTING_VPN (setting) && nm_streq (key, NM_SETTING_VPN_DATA))
|| (NM_IS_SETTING_VPN (setting) && nm_streq (key, NM_SETTING_VPN_SECRETS))
|| (NM_IS_SETTING_BOND (setting) && nm_streq (key, NM_SETTING_BOND_OPTIONS))
|| (NM_IS_SETTING_USER (setting) && nm_streq (key, NM_SETTING_USER_DATA)));
/* Write VPN secrets out to a different group to keep them separate */
if ( NM_IS_SETTING_VPN (setting)
&& nm_streq (key, NM_SETTING_VPN_SECRETS)) {
@ -2478,6 +2549,13 @@ static const ParseInfoSetting *const parse_infos[_NM_META_SETTING_TYPE_NUM] = {
PARSE_INFO_PROPERTY (NM_SETTING_WIRED_MAC_ADDRESS,
.parser = mac_address_parser_ETHER,
),
PARSE_INFO_PROPERTY (NM_SETTING_WIRED_S390_OPTIONS,
.parser_no_check_key = TRUE,
.parser_full = wired_s390_options_parser_full,
.writer_full = wired_s390_options_writer_full,
.has_parser_full = TRUE,
.has_writer_full = TRUE,
),
),
),
PARSE_INFO_SETTING (NM_META_SETTING_TYPE_BLUETOOTH,

View file

@ -75,7 +75,11 @@ typedef struct {
guint32 mtu;
char **s390_subchannels;
char *s390_nettype;
GHashTable *s390_options;
struct {
NMUtilsNamedValue *arr;
guint len;
guint n_alloc;
} s390_options;
NMSettingWiredWakeOnLan wol;
char *wol_password;
} NMSettingWiredPrivate;
@ -87,15 +91,68 @@ G_DEFINE_TYPE (NMSettingWired, nm_setting_wired, NM_TYPE_SETTING)
/*****************************************************************************/
static const char *valid_s390_opts[] = {
"portno", "layer2", "portname", "protocol", "priority_queueing",
"buffer_count", "isolation", "total", "inter", "inter_jumbo", "route4",
"route6", "fake_broadcast", "broadcast_mode", "canonical_macaddr",
"checksumming", "sniffer", "large_send", "ipato_enable", "ipato_invert4",
"ipato_add4", "ipato_invert6", "ipato_add6", "vipa_add4", "vipa_add6",
"rxip_add4", "rxip_add6", "lancmd_timeout", "ctcprot",
NULL
"broadcast_mode",
"buffer_count",
"canonical_macaddr",
"checksumming",
"ctcprot",
"fake_broadcast",
"inter",
"inter_jumbo",
"ipato_add4",
"ipato_add6",
"ipato_enable",
"ipato_invert4",
"ipato_invert6",
"isolation",
"lancmd_timeout",
"large_send",
"layer2",
"portname",
"portno",
"priority_queueing",
"protocol",
"route4",
"route6",
"rxip_add4",
"rxip_add6",
"sniffer",
"total",
"vipa_add4",
"vipa_add6",
NULL,
};
static gboolean
valid_s390_opts_check (const char *option)
{
#if NM_MORE_ASSERTS > 5
nm_assert (NM_PTRARRAY_LEN (valid_s390_opts) + 1 == G_N_ELEMENTS (valid_s390_opts));
{
gsize i;
for (i = 0; i < G_N_ELEMENTS (valid_s390_opts); i++) {
if (i == G_N_ELEMENTS (valid_s390_opts) - 1)
nm_assert (!valid_s390_opts[i]);
else {
nm_assert (valid_s390_opts[i]);
nm_assert (valid_s390_opts[i][0] != '\0');
if (i > 0)
g_assert (strcmp (valid_s390_opts[i - 1], valid_s390_opts[i]) < 0);
}
}
}
#endif
return option
&& (nm_utils_array_find_binary_search (valid_s390_opts,
sizeof (const char *),
G_N_ELEMENTS (valid_s390_opts) - 1,
&option,
nm_strcmp_p_with_data,
NULL) >= 0);
}
/**
* nm_setting_wired_get_port:
* @setting: the #NMSettingWired
@ -417,7 +474,7 @@ nm_setting_wired_get_num_s390_options (NMSettingWired *setting)
{
g_return_val_if_fail (NM_IS_SETTING_WIRED (setting), 0);
return g_hash_table_size (NM_SETTING_WIRED_GET_PRIVATE (setting)->s390_options);
return NM_SETTING_WIRED_GET_PRIVATE (setting)->s390_options.len;
}
/**
@ -447,24 +504,17 @@ nm_setting_wired_get_s390_option (NMSettingWired *setting,
const char **out_key,
const char **out_value)
{
const char *_key, *_value;
GHashTableIter iter;
guint i = 0;
NMSettingWiredPrivate *priv;
g_return_val_if_fail (NM_IS_SETTING_WIRED (setting), FALSE);
g_hash_table_iter_init (&iter, NM_SETTING_WIRED_GET_PRIVATE (setting)->s390_options);
while (g_hash_table_iter_next (&iter, (gpointer) &_key, (gpointer) &_value)) {
if (i == idx) {
if (out_key)
*out_key = _key;
if (out_value)
*out_value = _value;
return TRUE;
}
i++;
}
g_return_val_if_reached (FALSE);
priv = NM_SETTING_WIRED_GET_PRIVATE (setting);
g_return_val_if_fail (idx < priv->s390_options.len, FALSE);
NM_SET_OUT (out_key, priv->s390_options.arr[idx].name);
NM_SET_OUT (out_value, priv->s390_options.arr[idx].value_str);
return TRUE;
}
/**
@ -482,10 +532,21 @@ const char *
nm_setting_wired_get_s390_option_by_key (NMSettingWired *setting,
const char *key)
{
NMSettingWiredPrivate *priv;
gssize idx;
g_return_val_if_fail (NM_IS_SETTING_WIRED (setting), NULL);
g_return_val_if_fail (key && key[0], NULL);
return g_hash_table_lookup (NM_SETTING_WIRED_GET_PRIVATE (setting)->s390_options, key);
priv = NM_SETTING_WIRED_GET_PRIVATE (setting);
idx = nm_utils_named_value_list_find (priv->s390_options.arr,
priv->s390_options.len,
key,
TRUE);
if (idx < 0)
return NULL;
return priv->s390_options.arr[idx].value_str;
}
/**
@ -507,14 +568,51 @@ nm_setting_wired_add_s390_option (NMSettingWired *setting,
const char *key,
const char *value)
{
g_return_val_if_fail (NM_IS_SETTING_WIRED (setting), 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);
NMSettingWiredPrivate *priv;
gssize idx;
NMUtilsNamedValue *v;
g_return_val_if_fail (NM_IS_SETTING_WIRED (setting), FALSE);
g_return_val_if_fail (value, FALSE);
if (!valid_s390_opts_check (key)) {
g_return_val_if_fail (key, FALSE);
return FALSE;
}
priv = NM_SETTING_WIRED_GET_PRIVATE (setting);
idx = nm_utils_named_value_list_find (priv->s390_options.arr,
priv->s390_options.len,
key,
TRUE);
if (idx < 0) {
gsize dst_idx = ~idx;
if (priv->s390_options.n_alloc < priv->s390_options.len + 1) {
priv->s390_options.n_alloc = NM_MAX (4,
(priv->s390_options.len + 1) * 2);
priv->s390_options.arr = g_realloc (priv->s390_options.arr,
priv->s390_options.n_alloc * sizeof (NMUtilsNamedValue));
}
if (dst_idx < priv->s390_options.len) {
memmove (&priv->s390_options.arr[dst_idx + 1],
&priv->s390_options.arr[dst_idx],
(priv->s390_options.len - dst_idx) * sizeof (NMUtilsNamedValue));
}
priv->s390_options.arr[dst_idx] = (NMUtilsNamedValue) {
.name = g_strdup (key),
.value_str = g_strdup (value),
};
priv->s390_options.len++;
} else {
v = &priv->s390_options.arr[idx];
if (nm_streq (value, v->value_str))
return TRUE;
g_free ((char *) v->value_str);
v->value_str = g_strdup (value);
}
g_hash_table_insert (NM_SETTING_WIRED_GET_PRIVATE (setting)->s390_options,
g_strdup (key),
g_strdup (value));
_notify (setting, PROP_S390_OPTIONS);
return TRUE;
}
@ -534,20 +632,64 @@ gboolean
nm_setting_wired_remove_s390_option (NMSettingWired *setting,
const char *key)
{
gboolean found;
NMSettingWiredPrivate *priv;
gsize dst_idx;
gssize idx;
g_return_val_if_fail (NM_IS_SETTING_WIRED (setting), FALSE);
g_return_val_if_fail (key && key[0], FALSE);
g_return_val_if_fail (key, FALSE);
found = g_hash_table_remove (NM_SETTING_WIRED_GET_PRIVATE (setting)->s390_options, key);
if (found)
_notify (setting, PROP_S390_OPTIONS);
return found;
priv = NM_SETTING_WIRED_GET_PRIVATE (setting);
idx = nm_utils_named_value_list_find (priv->s390_options.arr,
priv->s390_options.len,
key,
TRUE);
if (idx < 0)
return FALSE;
dst_idx = idx;
g_free ((char *) priv->s390_options.arr[dst_idx].name);
g_free ((char *) priv->s390_options.arr[dst_idx].value_str);
if (dst_idx + 1 != priv->s390_options.len) {
memmove (&priv->s390_options.arr[dst_idx],
&priv->s390_options.arr[dst_idx + 1],
(priv->s390_options.len - dst_idx - 1) * sizeof (NMUtilsNamedValue));
}
priv->s390_options.len--;
_notify (setting, PROP_S390_OPTIONS);
return TRUE;
}
static void
_s390_options_clear (NMSettingWiredPrivate *priv)
{
guint i;
for (i = 0; i < priv->s390_options.len; i++) {
g_free ((char *) priv->s390_options.arr[i].name);
g_free ((char *) priv->s390_options.arr[i].value_str);
}
nm_clear_g_free (&priv->s390_options.arr);
priv->s390_options.len = 0;
priv->s390_options.n_alloc = 0;
}
void
_nm_setting_wired_clear_s390_options (NMSettingWired *setting)
{
g_return_if_fail (NM_IS_SETTING_WIRED (setting));
_s390_options_clear (NM_SETTING_WIRED_GET_PRIVATE (setting));
}
/**
* nm_setting_wired_get_valid_s390_options:
* @setting: (allow-none): the #NMSettingWired
* @setting: (allow-none): the #NMSettingWired. This argument is unused
* and you may pass %NULL.
*
* Returns a list of valid s390 options.
*
@ -602,10 +744,8 @@ static gboolean
verify (NMSetting *setting, NMConnection *connection, GError **error)
{
NMSettingWiredPrivate *priv = NM_SETTING_WIRED_GET_PRIVATE (setting);
GHashTableIter iter;
const char *key, *value;
int i;
GError *local = NULL;
guint i;
if (!NM_IN_STRSET (priv->port, NULL, "tp", "aui", "bnc", "mii")) {
g_set_error (error,
@ -672,16 +812,19 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
return FALSE;
}
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)
|| value[0] == '\0'
|| (strlen (value) > 200)) {
for (i = 0; i < priv->s390_options.len; i++) {
const NMUtilsNamedValue *v = &priv->s390_options.arr[i];
nm_assert (v->name);
if ( !valid_s390_opts_check (v->name)
|| v->value_str[0] == '\0'
|| strlen (v->value_str) > 200) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("invalid '%s' or its value '%s'"),
key, value);
v->name, v->value_str);
g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_S390_OPTIONS);
return FALSE;
}
@ -802,6 +945,8 @@ get_property (GObject *object, guint prop_id,
{
NMSettingWired *setting = NM_SETTING_WIRED (object);
NMSettingWiredPrivate *priv = NM_SETTING_WIRED_GET_PRIVATE (setting);
GHashTable *hash;
guint i;
switch (prop_id) {
case PROP_PORT:
@ -838,7 +983,16 @@ get_property (GObject *object, guint prop_id,
g_value_set_string (value, nm_setting_wired_get_s390_nettype (setting));
break;
case PROP_S390_OPTIONS:
g_value_take_boxed (value, _nm_utils_copy_strdict (priv->s390_options));
hash = g_hash_table_new_full (nm_str_hash,
g_str_equal,
g_free,
g_free);
for (i = 0; i < priv->s390_options.len; i++) {
g_hash_table_insert (hash,
g_strdup (priv->s390_options.arr[i].name),
g_strdup (priv->s390_options.arr[i].value_str));
}
g_value_take_boxed (value, hash);
break;
case PROP_WAKE_ON_LAN:
g_value_set_uint (value, priv->wol);
@ -859,7 +1013,6 @@ set_property (GObject *object, guint prop_id,
NMSettingWiredPrivate *priv = NM_SETTING_WIRED_GET_PRIVATE (object);
const char * const *blacklist;
const char *mac;
int i;
switch (prop_id) {
case PROP_PORT:
@ -894,6 +1047,8 @@ set_property (GObject *object, guint prop_id,
blacklist = g_value_get_boxed (value);
g_array_set_size (priv->mac_address_blacklist, 0);
if (blacklist && *blacklist) {
guint i;
for (i = 0; blacklist[i]; i++) {
mac = _nm_utils_hwaddr_canonical_or_invalid (blacklist[i], ETH_ALEN);
g_array_append_val (priv->mac_address_blacklist, mac);
@ -913,8 +1068,63 @@ set_property (GObject *object, guint prop_id,
priv->s390_nettype = g_value_dup_string (value);
break;
case PROP_S390_OPTIONS:
g_hash_table_unref (priv->s390_options);
priv->s390_options = _nm_utils_copy_strdict (g_value_get_boxed (value));
{
GHashTable *hash;
_s390_options_clear (priv);
hash = g_value_get_boxed (value);
priv->s390_options.n_alloc = hash ? g_hash_table_size (hash) : 0u;
if (priv->s390_options.n_alloc > 0) {
gboolean invalid_content = FALSE;
GHashTableIter iter;
const char *key;
const char *val;
guint i, j;
priv->s390_options.arr = g_new (NMUtilsNamedValue, priv->s390_options.n_alloc);
g_hash_table_iter_init (&iter, hash);
while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &val)) {
if (!key || !val) {
invalid_content = TRUE;
continue;
}
nm_assert (priv->s390_options.len < priv->s390_options.n_alloc);
priv->s390_options.arr[priv->s390_options.len] = (NMUtilsNamedValue) {
.name = g_strdup (key),
.value_str = g_strdup (val),
};
priv->s390_options.len++;
}
if (priv->s390_options.len > 1) {
nm_utils_named_value_list_sort (priv->s390_options.arr,
priv->s390_options.len,
NULL,
NULL);
/* prune duplicate keys. This is only possible if @hash does not use
* g_str_equal() as compare function (which would be a bug).
* Still, handle this, because we use later binary sort and rely
* on unique names. One bug here, should not bork the remainder
* of the program. */
j = 1;
for (i = 1; i < priv->s390_options.len; i++) {
if (nm_streq (priv->s390_options.arr[j - 1].name,
priv->s390_options.arr[i].name)) {
g_free ((char *) priv->s390_options.arr[i].name);
g_free ((char *) priv->s390_options.arr[i].value_str);
invalid_content = TRUE;
continue;
}
priv->s390_options.arr[j++] = priv->s390_options.arr[i];
}
priv->s390_options.len = j;
}
g_return_if_fail (!invalid_content);
}
}
break;
case PROP_WAKE_ON_LAN:
priv->wol = g_value_get_uint (value);
@ -936,8 +1146,6 @@ nm_setting_wired_init (NMSettingWired *setting)
{
NMSettingWiredPrivate *priv = NM_SETTING_WIRED_GET_PRIVATE (setting);
priv->s390_options = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_free);
/* We use GArray rather than GPtrArray so it will automatically be NULL-terminated */
priv->mac_address_blacklist = g_array_new (TRUE, FALSE, sizeof (char *));
g_array_set_clear_func (priv->mac_address_blacklist, (GDestroyNotify) clear_blacklist_item);
@ -965,7 +1173,7 @@ finalize (GObject *object)
g_free (priv->duplex);
g_free (priv->s390_nettype);
g_hash_table_destroy (priv->s390_options);
_s390_options_clear (priv);
g_free (priv->device_mac_address);
g_free (priv->cloned_mac_address);

View file

@ -851,8 +851,7 @@ _nm_utils_strdict_to_dbus (const GValue *prop_value)
} while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value));
nm_assert (i == len);
g_qsort_with_data (idx, len, sizeof (idx[0]),
nm_utils_named_entry_cmp_with_data, NULL);
nm_utils_named_value_list_sort (idx, len, NULL, NULL);
for (i = 0; i < len; i++)
g_variant_builder_add (&builder, "{ss}", idx[i].name, idx[i].value_str);

View file

@ -2108,6 +2108,105 @@ test_tc_config_dbus (void)
/*****************************************************************************/
static void
_rndt_wired_add_s390_options (NMSettingWired *s_wired,
char **out_keyfile_entries)
{
gsize n_opts;
gsize i, j;
const char *const*option_names;
gs_free const char **opt_keys = NULL;
gs_strfreev char **opt_vals = NULL;
gs_free bool *opt_found = NULL;
GString *keyfile_entries;
nm_auto_free_gstring GString *str_tmp = NULL;
option_names = nm_setting_wired_get_valid_s390_options (nmtst_get_rand_bool () ? NULL : s_wired);
n_opts = NM_PTRARRAY_LEN (option_names);
opt_keys = g_new (const char *, (n_opts + 1));
nmtst_rand_perm (NULL, opt_keys, option_names, sizeof (const char *), n_opts);
n_opts = nmtst_get_rand_int () % (n_opts + 1);
opt_keys[n_opts] = NULL;
opt_vals = g_new0 (char *, n_opts + 1);
opt_found = g_new0 (bool, n_opts + 1);
for (i = 0; i < n_opts; i++) {
guint p = nmtst_get_rand_int () % 1000;
if (p < 200)
opt_vals[i] = nm_strdup_int (i);
else {
opt_vals[i] = g_strdup_printf ("%s%s%s%s-%zu",
((p % 5) % 2) ? "\n" : "",
((p % 7) % 2) ? "\t" : "",
((p % 11) % 2) ? "x" : "",
((p % 13) % 2) ? "=" : "",
i);
}
}
if (nmtst_get_rand_bool ()) {
gs_unref_hashtable GHashTable *hash = NULL;
hash = g_hash_table_new (nm_str_hash, g_str_equal);
for (i = 0; i < n_opts; i++)
g_hash_table_insert (hash, (char *) opt_keys[i], opt_vals[i]);
g_object_set (s_wired,
NM_SETTING_WIRED_S390_OPTIONS,
hash,
NULL);
} else {
_nm_setting_wired_clear_s390_options (s_wired);
for (i = 0; i < n_opts; i++) {
if (!nm_setting_wired_add_s390_option (s_wired, opt_keys[i], opt_vals[i]))
g_assert_not_reached ();
}
}
g_assert_cmpint (nm_setting_wired_get_num_s390_options (s_wired), ==, n_opts);
keyfile_entries = g_string_new (NULL);
str_tmp = g_string_new (NULL);
if (n_opts > 0)
g_string_append_printf (keyfile_entries, "[ethernet-s390-options]\n");
for (i = 0; i < n_opts; i++) {
gssize idx;
const char *k, *v;
nm_setting_wired_get_s390_option (s_wired, i, &k, &v);
g_assert (k);
g_assert (v);
idx = nm_utils_strv_find_first ((char **) opt_keys, n_opts, k);
g_assert (idx >= 0);
g_assert (!opt_found[idx]);
opt_found[idx] = TRUE;
g_assert_cmpstr (opt_keys[idx], ==, k);
g_assert_cmpstr (opt_vals[idx], ==, v);
g_string_truncate (str_tmp, 0);
for (j = 0; v[j] != '\0'; j++) {
if (v[j] == '\n')
g_string_append (str_tmp, "\\n");
else if (v[j] == '\t')
g_string_append (str_tmp, "\\t");
else
g_string_append_c (str_tmp, v[j]);
}
g_string_append_printf (keyfile_entries,
"%s=%s\n",
k,
str_tmp->str);
}
for (i = 0; i < n_opts; i++)
g_assert (opt_found[i]);
if (n_opts > 0)
g_string_append_printf (keyfile_entries, "\n");
*out_keyfile_entries = g_string_free (keyfile_entries, FALSE);
}
static GPtrArray *
_rndt_wg_peers_create (void)
{
@ -2385,6 +2484,7 @@ test_roundtrip_conversion (gconstpointer test_data)
int is_ipv4;
guint i;
gboolean success;
gs_free char *s390_keyfile_entries = NULL;
switch (MODE) {
case 0:
@ -2403,6 +2503,8 @@ test_roundtrip_conversion (gconstpointer test_data)
ETH_MTU,
NULL);
_rndt_wired_add_s390_options (s_eth, &s390_keyfile_entries);
g_ptr_array_add (kf_data_arr,
g_strdup_printf ("[connection]\n"
"id=%s\n"
@ -2415,6 +2517,7 @@ test_roundtrip_conversion (gconstpointer test_data)
"mac-address-blacklist=\n"
"%s" /* mtu */
"\n"
"%s" /* [ethernet-s390-options] */
"[ipv4]\n"
"dns-search=\n"
"method=auto\n"
@ -2429,7 +2532,8 @@ test_roundtrip_conversion (gconstpointer test_data)
INTERFACE_NAME,
(ETH_MTU != 0)
? nm_sprintf_bufa (100, "mtu=%u\n", ETH_MTU)
: ""));
: "",
s390_keyfile_entries));
g_ptr_array_add (kf_data_arr,
g_strdup_printf ("[connection]\n"
@ -2443,6 +2547,7 @@ test_roundtrip_conversion (gconstpointer test_data)
"mac-address-blacklist=\n"
"%s" /* mtu */
"\n"
"%s" /* [ethernet-s390-options] */
"[ipv4]\n"
"dns-search=\n"
"method=auto\n"
@ -2457,7 +2562,8 @@ test_roundtrip_conversion (gconstpointer test_data)
INTERFACE_NAME,
(ETH_MTU != 0)
? nm_sprintf_bufa (100, "mtu=%d\n", (int) ETH_MTU)
: ""));
: "",
s390_keyfile_entries));
break;
@ -2703,6 +2809,9 @@ test_roundtrip_conversion (gconstpointer test_data)
g_assert_cmpint (nm_setting_wired_get_mtu (s_eth), ==, ETH_MTU);
g_assert_cmpint (nm_setting_wired_get_mtu (s_eth2), ==, ETH_MTU);
g_assert_cmpint (nm_setting_wired_get_num_s390_options (s_eth2), ==, nm_setting_wired_get_num_s390_options (s_eth));
break;
case 1:

View file

@ -138,6 +138,7 @@ libnm/nm-vpn-plugin-old.c
libnm/nm-vpn-service-plugin.c
data/org.freedesktop.NetworkManager.policy.in.in
shared/nm-glib-aux/nm-shared-utils.c
shared/nm-libnm-core-aux/nm-libnm-core-aux.c
src/NetworkManagerUtils.c
src/main.c
src/main-utils.c

View file

@ -287,18 +287,21 @@ libnm_systemd_shared_no_logging_dep = declare_dependency(
###############################################################################
test_shared_general = executable(
'nm-utils/tests/test-shared-general',
[ 'nm-utils/tests/test-shared-general.c', ],
c_args: [
'-DNETWORKMANAGER_COMPILATION_TEST',
'-DNETWORKMANAGER_COMPILATION=(NM_NETWORKMANAGER_COMPILATION_GLIB|NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG)',
exe = executable(
'nm-utils/tests/test-shared-general',
[ 'nm-utils/tests/test-shared-general.c' ],
c_args: [
'-DNETWORKMANAGER_COMPILATION_TEST',
'-DNETWORKMANAGER_COMPILATION=(NM_NETWORKMANAGER_COMPILATION_GLIB|NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG)',
],
dependencies: [
shared_nm_glib_aux_dep,
shared_c_siphash_dep,
],
dependencies: shared_nm_glib_aux_dep,
link_with: shared_c_siphash,
)
test(
'shared/nm-utils/test-shared-general',
test_script,
args: test_args + [test_shared_general.full_path()]
'shared/nm-utils/tests/test-shared-general',
test_script,
args: test_args + [exe.full_path()]
)

View file

@ -2130,6 +2130,8 @@ nm_utils_fd_read_loop_exact (int fd, void *buf, size_t nbytes, bool do_poll)
return 0;
}
/*****************************************************************************/
NMUtilsNamedValue *
nm_utils_named_values_from_str_dict (GHashTable *hash, guint *out_len)
{
@ -2154,15 +2156,106 @@ nm_utils_named_values_from_str_dict (GHashTable *hash, guint *out_len)
values[i].name = NULL;
values[i].value_ptr = NULL;
if (len > 1) {
g_qsort_with_data (values, len, sizeof (values[0]),
nm_utils_named_entry_cmp_with_data, NULL);
}
nm_utils_named_value_list_sort (values, len, NULL, NULL);
NM_SET_OUT (out_len, len);
return values;
}
gssize
nm_utils_named_value_list_find (const NMUtilsNamedValue *arr,
gsize len,
const char *name,
gboolean sorted)
{
gsize i;
nm_assert (name);
#if NM_MORE_ASSERTS > 5
{
for (i = 0; i < len; i++) {
const NMUtilsNamedValue *v = &arr[i];
nm_assert (v->name);
if ( sorted
&& i > 0)
nm_assert (strcmp (arr[i - 1].name, v->name) < 0);
}
}
nm_assert ( !sorted
|| nm_utils_named_value_list_is_sorted (arr, len, FALSE, NULL, NULL));
#endif
if (sorted) {
return nm_utils_array_find_binary_search (arr,
sizeof (NMUtilsNamedValue),
len,
&name,
nm_strcmp_p_with_data,
NULL);
}
for (i = 0; i < len; i++) {
if (nm_streq (arr[i].name, name))
return i;
}
return ~((gssize) len);
}
gboolean
nm_utils_named_value_list_is_sorted (const NMUtilsNamedValue *arr,
gsize len,
gboolean accept_duplicates,
GCompareDataFunc compare_func,
gpointer user_data)
{
gsize i;
int c_limit;
if (len == 0)
return TRUE;
g_return_val_if_fail (arr, FALSE);
if (!compare_func)
compare_func = nm_strcmp_p_with_data;
c_limit = accept_duplicates ? 0 : -1;
for (i = 1; i < len; i++) {
int c;
c = compare_func (&arr[i - 1], &arr[i], user_data);
if (c > c_limit)
return FALSE;
}
return TRUE;
}
void
nm_utils_named_value_list_sort (NMUtilsNamedValue *arr,
gsize len,
GCompareDataFunc compare_func,
gpointer user_data)
{
if (len == 0)
return;
g_return_if_fail (arr);
if (len == 1)
return;
g_qsort_with_data (arr,
len,
sizeof (NMUtilsNamedValue),
compare_func ?: nm_strcmp_p_with_data,
user_data);
}
/*****************************************************************************/
gpointer *
nm_utils_hash_keys_to_array (GHashTable *hash,
GCompareDataFunc compare_func,

View file

@ -906,11 +906,26 @@ typedef struct {
};
} NMUtilsNamedValue;
#define nm_utils_named_entry_cmp nm_strcmp_p
#define nm_utils_named_entry_cmp_with_data nm_strcmp_p_with_data
NMUtilsNamedValue *nm_utils_named_values_from_str_dict (GHashTable *hash, guint *out_len);
gssize nm_utils_named_value_list_find (const NMUtilsNamedValue *arr,
gsize len,
const char *name,
gboolean sorted);
gboolean nm_utils_named_value_list_is_sorted (const NMUtilsNamedValue *arr,
gsize len,
gboolean accept_duplicates,
GCompareDataFunc compare_func,
gpointer user_data);
void nm_utils_named_value_list_sort (NMUtilsNamedValue *arr,
gsize len,
GCompareDataFunc compare_func,
gpointer user_data);
/*****************************************************************************/
gpointer *nm_utils_hash_keys_to_array (GHashTable *hash,
GCompareDataFunc compare_func,
gpointer user_data,

View file

@ -0,0 +1,372 @@
/* NetworkManager -- Network link manager
*
* 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.
*
* (C) Copyright 2019 Red Hat, Inc.
*/
#include "nm-default.h"
#include "nm-libnm-core-aux.h"
#include "nm-libnm-core-intern/nm-libnm-core-utils.h"
/*****************************************************************************/
typedef enum {
KEY_TYPE_STRING,
KEY_TYPE_INT,
KEY_TYPE_BOOL,
} KeyType;
typedef struct {
const char *str_val;
union {
int vint;
bool vbool;
} typ_val;
} ParseData;
typedef struct {
const char *name;
NMTeamLinkWatcherType watcher_type;
KeyType key_type;
union {
int (*fint) (NMTeamLinkWatcher *watcher);
gboolean (*fbool) (NMTeamLinkWatcher *watcher);
const char *(*fstring) (NMTeamLinkWatcher *watcher);
} get_fcn;
union {
int vint;
bool vbool;
} def_val;
} TeamLinkWatcherKeyInfo;
static gboolean
_team_link_watcher_validate_active (NMTeamLinkWatcher *watcher)
{
return NM_FLAGS_HAS (nm_team_link_watcher_get_flags (watcher), NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE);
}
static gboolean
_team_link_watcher_validate_inactive (NMTeamLinkWatcher *watcher)
{
return NM_FLAGS_HAS (nm_team_link_watcher_get_flags (watcher), NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE);
}
static gboolean
_team_link_watcher_send_always (NMTeamLinkWatcher *watcher)
{
return NM_FLAGS_HAS (nm_team_link_watcher_get_flags (watcher), NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS);
}
static const TeamLinkWatcherKeyInfo _team_link_watcher_key_infos[_NM_TEAM_LINK_WATCHER_KEY_NUM] = {
#define _KEY_INFO(key_id, _name, _watcher_type, _key_type, ...) \
[key_id] = { .name = ""_name"", .watcher_type = (_watcher_type), .key_type = _key_type, ##__VA_ARGS__ }
_KEY_INFO (NM_TEAM_LINK_WATCHER_KEY_NAME, "name", NM_TEAM_LINK_WATCHER_TYPE_ETHTOOL | NM_TEAM_LINK_WATCHER_TYPE_NSNAPING | NM_TEAM_LINK_WATCHER_TYPE_ARPING, KEY_TYPE_STRING, .get_fcn.fstring = nm_team_link_watcher_get_name, ),
_KEY_INFO (NM_TEAM_LINK_WATCHER_KEY_DELAY_UP, "delay-up", NM_TEAM_LINK_WATCHER_TYPE_ETHTOOL, KEY_TYPE_INT, .get_fcn.fint = nm_team_link_watcher_get_delay_up, ),
_KEY_INFO (NM_TEAM_LINK_WATCHER_KEY_DELAY_DOWN, "delay-down", NM_TEAM_LINK_WATCHER_TYPE_ETHTOOL, KEY_TYPE_INT, .get_fcn.fint = nm_team_link_watcher_get_delay_down, ),
_KEY_INFO (NM_TEAM_LINK_WATCHER_KEY_INIT_WAIT, "init-wait", NM_TEAM_LINK_WATCHER_TYPE_NSNAPING | NM_TEAM_LINK_WATCHER_TYPE_ARPING, KEY_TYPE_INT, .get_fcn.fint = nm_team_link_watcher_get_init_wait, ),
_KEY_INFO (NM_TEAM_LINK_WATCHER_KEY_INTERVAL, "interval", NM_TEAM_LINK_WATCHER_TYPE_NSNAPING | NM_TEAM_LINK_WATCHER_TYPE_ARPING, KEY_TYPE_INT, .get_fcn.fint = nm_team_link_watcher_get_interval, ),
_KEY_INFO (NM_TEAM_LINK_WATCHER_KEY_MISSED_MAX, "missed-max", NM_TEAM_LINK_WATCHER_TYPE_NSNAPING | NM_TEAM_LINK_WATCHER_TYPE_ARPING, KEY_TYPE_INT, .get_fcn.fint = nm_team_link_watcher_get_missed_max, .def_val.vint = 3, ),
_KEY_INFO (NM_TEAM_LINK_WATCHER_KEY_TARGET_HOST, "target-host", NM_TEAM_LINK_WATCHER_TYPE_NSNAPING | NM_TEAM_LINK_WATCHER_TYPE_ARPING, KEY_TYPE_STRING, .get_fcn.fstring = nm_team_link_watcher_get_target_host, ),
_KEY_INFO (NM_TEAM_LINK_WATCHER_KEY_VLANID, "vlanid", NM_TEAM_LINK_WATCHER_TYPE_ARPING, KEY_TYPE_INT, .get_fcn.fint = nm_team_link_watcher_get_vlanid, .def_val.vint = -1, ),
_KEY_INFO (NM_TEAM_LINK_WATCHER_KEY_SOURCE_HOST, "source-host", NM_TEAM_LINK_WATCHER_TYPE_ARPING, KEY_TYPE_STRING, .get_fcn.fstring = nm_team_link_watcher_get_source_host, ),
_KEY_INFO (NM_TEAM_LINK_WATCHER_KEY_VALIDATE_ACTIVE, "validate-active", NM_TEAM_LINK_WATCHER_TYPE_ARPING, KEY_TYPE_BOOL, .get_fcn.fbool = _team_link_watcher_validate_active, ),
_KEY_INFO (NM_TEAM_LINK_WATCHER_KEY_VALIDATE_INACTIVE, "validate-inactive", NM_TEAM_LINK_WATCHER_TYPE_ARPING, KEY_TYPE_BOOL, .get_fcn.fbool = _team_link_watcher_validate_inactive, ),
_KEY_INFO (NM_TEAM_LINK_WATCHER_KEY_SEND_ALWAYS, "send-always", NM_TEAM_LINK_WATCHER_TYPE_ARPING, KEY_TYPE_BOOL, .get_fcn.fbool = _team_link_watcher_send_always, ),
};
static NMTeamLinkWatcherType
_team_link_watcher_get_watcher_type_from_name (const char *name)
{
if (name) {
if (nm_streq (name, NM_TEAM_LINK_WATCHER_ETHTOOL))
return NM_TEAM_LINK_WATCHER_TYPE_ETHTOOL;
if (nm_streq (name, NM_TEAM_LINK_WATCHER_NSNA_PING))
return NM_TEAM_LINK_WATCHER_TYPE_NSNAPING;
if (nm_streq (name, NM_TEAM_LINK_WATCHER_ARP_PING))
return NM_TEAM_LINK_WATCHER_TYPE_ARPING;
}
return NM_TEAM_LINK_WATCHER_TYPE_NONE;
}
static const char *
_parse_data_get_str (const ParseData parse_data[static _NM_TEAM_LINK_WATCHER_KEY_NUM],
NMTeamLinkWatcherKeyId key_id)
{
nm_assert (_NM_INT_NOT_NEGATIVE (key_id) && key_id < _NM_TEAM_LINK_WATCHER_KEY_NUM);
nm_assert (_team_link_watcher_key_infos[key_id].key_type == KEY_TYPE_STRING);
return parse_data[key_id].str_val;
}
static int
_parse_data_get_int (const ParseData parse_data[static _NM_TEAM_LINK_WATCHER_KEY_NUM],
NMTeamLinkWatcherKeyId key_id)
{
nm_assert (_NM_INT_NOT_NEGATIVE (key_id) && key_id < _NM_TEAM_LINK_WATCHER_KEY_NUM);
nm_assert (_team_link_watcher_key_infos[key_id].key_type == KEY_TYPE_INT);
if (parse_data[key_id].str_val)
return parse_data[key_id].typ_val.vint;
return _team_link_watcher_key_infos[key_id].def_val.vint;
}
static int
_parse_data_get_bool (const ParseData parse_data[static _NM_TEAM_LINK_WATCHER_KEY_NUM],
NMTeamLinkWatcherKeyId key_id)
{
nm_assert (_NM_INT_NOT_NEGATIVE (key_id) && key_id < _NM_TEAM_LINK_WATCHER_KEY_NUM);
nm_assert (_team_link_watcher_key_infos[key_id].key_type == KEY_TYPE_BOOL);
if (parse_data[key_id].str_val)
return parse_data[key_id].typ_val.vbool;
return _team_link_watcher_key_infos[key_id].def_val.vbool;
}
char *
nm_utils_team_link_watcher_to_string (NMTeamLinkWatcher *watcher)
{
nm_auto_free_gstring GString *str = NULL;
const char *name;
NMTeamLinkWatcherType watcher_type;
NMTeamLinkWatcherKeyId key_id;
if (!watcher)
return NULL;
str = g_string_new (NULL);
name = nm_team_link_watcher_get_name (watcher);
g_string_append_printf (str, "name=%s", name ?: "");
watcher_type = _team_link_watcher_get_watcher_type_from_name (name);
for (key_id = 0; key_id < _NM_TEAM_LINK_WATCHER_KEY_NUM; key_id++) {
const TeamLinkWatcherKeyInfo *info = &_team_link_watcher_key_infos[key_id];
const char *vstr;
int vint;
bool vbool;
nm_assert (info->name && info->name && NM_STRCHAR_ALL (info->name, ch,((ch >= 'a' && ch <= 'z') || NM_IN_SET (ch, '-'))));
nm_assert (NM_IN_SET (info->key_type, KEY_TYPE_STRING,
KEY_TYPE_INT,
KEY_TYPE_BOOL));
if (key_id == NM_TEAM_LINK_WATCHER_KEY_NAME)
continue;
if (!NM_FLAGS_ALL (info->watcher_type, watcher_type))
continue;
switch (info->key_type) {
case KEY_TYPE_STRING:
vstr = info->get_fcn.fstring (watcher);
if (vstr) {
g_string_append_printf (nm_gstring_add_space_delimiter (str),
"%s=%s", info->name, vstr);
}
break;
case KEY_TYPE_INT:
vint = info->get_fcn.fint (watcher);
if (vint != info->def_val.vint) {
g_string_append_printf (nm_gstring_add_space_delimiter (str),
"%s=%d", info->name, vint);
}
break;
case KEY_TYPE_BOOL:
vbool = info->get_fcn.fbool (watcher);
if (vbool != info->def_val.vbool) {
g_string_append_printf (nm_gstring_add_space_delimiter (str),
"%s=%s", info->name, vbool ? "true" : "false");
}
break;
}
}
return g_string_free (g_steal_pointer (&str), FALSE);
}
NMTeamLinkWatcher *
nm_utils_team_link_watcher_from_string (const char *str,
GError **error)
{
gs_free const char **tokens = NULL;
ParseData parse_data[_NM_TEAM_LINK_WATCHER_KEY_NUM] = { };
NMTeamLinkWatcherType watcher_type;
NMTeamLinkWatcherKeyId key_id;
gsize i_token;
NMTeamLinkWatcher *watcher;
int errsv;
g_return_val_if_fail (str, NULL);
g_return_val_if_fail (!error || !*error, NULL);
tokens = nm_utils_escaped_tokens_split (str, NM_ASCII_SPACES);
if (!tokens) {
g_set_error (error, 1, 0, "'%s' is not valid", str);
return NULL;
}
for (i_token = 0; tokens[i_token]; i_token++) {
const TeamLinkWatcherKeyInfo *info;
const char *key = tokens[i_token];
const char *val;
val = strchr (key, '=');
if (!val) {
nm_utils_error_set (error, NM_UTILS_ERROR_UNKNOWN,
_("'%s' is not valid: properties should be specified as 'key=value'"),
key);
return NULL;
}
((char *) val)[0] = '\0';
val++;
for (key_id = 0; key_id < _NM_TEAM_LINK_WATCHER_KEY_NUM; key_id++) {
info = &_team_link_watcher_key_infos[key_id];
if (nm_streq (key, info->name))
break;
}
if (key_id == _NM_TEAM_LINK_WATCHER_KEY_NUM) {
nm_utils_error_set (error, NM_UTILS_ERROR_UNKNOWN,
_("'%s' is not a valid key"), key);
return NULL;
}
if (parse_data[key_id].str_val) {
nm_utils_error_set (error, NM_UTILS_ERROR_UNKNOWN,
_("duplicate key '%s'"), key);
return NULL;
}
parse_data[key_id].str_val = val;
if (info->key_type == KEY_TYPE_INT) {
gint64 v64;
v64 = _nm_utils_ascii_str_to_int64 (val, 10, G_MININT, G_MAXINT, G_MAXINT64);
if ( v64 == G_MAXINT64
&& ((errsv = errno) != 0)) {
if (errsv == ERANGE) {
nm_utils_error_set (error, NM_UTILS_ERROR_UNKNOWN,
_("number for '%s' is out of range"), key);
} else {
nm_utils_error_set (error, NM_UTILS_ERROR_UNKNOWN,
_("value for '%s' must be a number"), key);
}
return NULL;
}
parse_data[key_id].typ_val.vint = v64;
} else if (info->key_type == KEY_TYPE_BOOL) {
int vbool;
vbool = _nm_utils_ascii_str_to_bool (val, -1);
if (vbool == -1) {
nm_utils_error_set (error, NM_UTILS_ERROR_UNKNOWN,
_("value for '%s' must be a boolean"), key);
return NULL;
}
parse_data[key_id].typ_val.vbool = vbool;
}
}
if (!parse_data[NM_TEAM_LINK_WATCHER_KEY_NAME].str_val) {
nm_utils_error_set (error, NM_UTILS_ERROR_UNKNOWN,
_("missing 'name' attribute"));
return NULL;
}
watcher_type = _team_link_watcher_get_watcher_type_from_name (parse_data[NM_TEAM_LINK_WATCHER_KEY_NAME].str_val);
if (watcher_type == NM_TEAM_LINK_WATCHER_TYPE_NONE) {
nm_utils_error_set (error, NM_UTILS_ERROR_UNKNOWN,
_("invalid 'name' \"%s\""),
parse_data[NM_TEAM_LINK_WATCHER_KEY_NAME].str_val);
return NULL;
}
for (key_id = 0; key_id < _NM_TEAM_LINK_WATCHER_KEY_NUM; key_id++) {
const TeamLinkWatcherKeyInfo *info = &_team_link_watcher_key_infos[key_id];
if (!parse_data[key_id].str_val)
continue;
if (!NM_FLAGS_ALL (info->watcher_type, watcher_type)) {
nm_utils_error_set (error, NM_UTILS_ERROR_UNKNOWN,
_("attribute '%s' is invalid for \"%s\""),
info->name,
parse_data[NM_TEAM_LINK_WATCHER_KEY_NAME].str_val);
return NULL;
}
}
switch (watcher_type) {
case NM_TEAM_LINK_WATCHER_TYPE_ETHTOOL:
watcher = nm_team_link_watcher_new_ethtool (_parse_data_get_int (parse_data, NM_TEAM_LINK_WATCHER_KEY_DELAY_UP),
_parse_data_get_int (parse_data, NM_TEAM_LINK_WATCHER_KEY_DELAY_DOWN),
error);
break;
case NM_TEAM_LINK_WATCHER_TYPE_NSNAPING:
watcher = nm_team_link_watcher_new_nsna_ping (_parse_data_get_int (parse_data, NM_TEAM_LINK_WATCHER_KEY_INIT_WAIT),
_parse_data_get_int (parse_data, NM_TEAM_LINK_WATCHER_KEY_INTERVAL),
_parse_data_get_int (parse_data, NM_TEAM_LINK_WATCHER_KEY_MISSED_MAX),
_parse_data_get_str (parse_data, NM_TEAM_LINK_WATCHER_KEY_TARGET_HOST),
error);
break;
default:
nm_assert (watcher_type == NM_TEAM_LINK_WATCHER_TYPE_ARPING);
watcher = nm_team_link_watcher_new_arp_ping2 (_parse_data_get_int (parse_data, NM_TEAM_LINK_WATCHER_KEY_INIT_WAIT),
_parse_data_get_int (parse_data, NM_TEAM_LINK_WATCHER_KEY_INTERVAL),
_parse_data_get_int (parse_data, NM_TEAM_LINK_WATCHER_KEY_MISSED_MAX),
_parse_data_get_int (parse_data, NM_TEAM_LINK_WATCHER_KEY_VLANID),
_parse_data_get_str (parse_data, NM_TEAM_LINK_WATCHER_KEY_TARGET_HOST),
_parse_data_get_str (parse_data, NM_TEAM_LINK_WATCHER_KEY_SOURCE_HOST),
( NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE
| (_parse_data_get_bool (parse_data, NM_TEAM_LINK_WATCHER_KEY_VALIDATE_ACTIVE) ? NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE : NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE)
| (_parse_data_get_bool (parse_data, NM_TEAM_LINK_WATCHER_KEY_VALIDATE_INACTIVE) ? NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE : NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE)
| (_parse_data_get_bool (parse_data, NM_TEAM_LINK_WATCHER_KEY_SEND_ALWAYS) ? NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS : NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE)
),
error);
break;
}
#if NM_MORE_ASSERTS > 5
{
gs_free char *str2 = NULL;
nm_auto_unref_team_link_watcher NMTeamLinkWatcher *watcher2 = NULL;
static _nm_thread_local int recursive;
nm_assert (watcher);
if (recursive == 0) {
recursive = 1;
str2 = nm_utils_team_link_watcher_to_string (watcher);
nm_assert (str2);
watcher2 = nm_utils_team_link_watcher_from_string (str2, NULL);
nm_assert (watcher2);
nm_assert (nm_team_link_watcher_equal (watcher, watcher2));
nm_assert (nm_team_link_watcher_equal (watcher2, watcher));
nm_assert (recursive == 1);
recursive = 0;
}
}
#endif
return watcher;
}

View file

@ -0,0 +1,54 @@
/* NetworkManager -- Network link manager
*
* 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.
*
* (C) Copyright 2019 Red Hat, Inc.
*/
#ifndef __NM_LIBNM_CORE_AUX_H__
#define __NM_LIBNM_CORE_AUX_H__
#include "nm-setting-team.h"
typedef enum {
NM_TEAM_LINK_WATCHER_TYPE_NONE = 0,
NM_TEAM_LINK_WATCHER_TYPE_ETHTOOL = (1u << 0),
NM_TEAM_LINK_WATCHER_TYPE_NSNAPING = (1u << 1),
NM_TEAM_LINK_WATCHER_TYPE_ARPING = (1u << 2),
} NMTeamLinkWatcherType;
typedef enum {
NM_TEAM_LINK_WATCHER_KEY_NAME,
NM_TEAM_LINK_WATCHER_KEY_DELAY_UP,
NM_TEAM_LINK_WATCHER_KEY_DELAY_DOWN,
NM_TEAM_LINK_WATCHER_KEY_INIT_WAIT,
NM_TEAM_LINK_WATCHER_KEY_INTERVAL,
NM_TEAM_LINK_WATCHER_KEY_MISSED_MAX,
NM_TEAM_LINK_WATCHER_KEY_TARGET_HOST,
NM_TEAM_LINK_WATCHER_KEY_VLANID,
NM_TEAM_LINK_WATCHER_KEY_SOURCE_HOST,
NM_TEAM_LINK_WATCHER_KEY_VALIDATE_ACTIVE,
NM_TEAM_LINK_WATCHER_KEY_VALIDATE_INACTIVE,
NM_TEAM_LINK_WATCHER_KEY_SEND_ALWAYS,
_NM_TEAM_LINK_WATCHER_KEY_NUM,
} NMTeamLinkWatcherKeyId;
char *nm_utils_team_link_watcher_to_string (NMTeamLinkWatcher *watcher);
NMTeamLinkWatcher *nm_utils_team_link_watcher_from_string (const char *str,
GError **error);
#endif /* __NM_LIBNM_CORE_AUX_H__ */

View file

@ -461,4 +461,3 @@ int main (int argc, char **argv)
return g_test_run ();
}

View file

@ -1575,11 +1575,11 @@ update_connection (NMDevice *device, NMConnection *connection)
g_object_set (s_wired, NM_SETTING_WIRED_S390_SUBCHANNELS, priv->subchannels_dbus, NULL);
if (priv->s390_nettype)
g_object_set (s_wired, NM_SETTING_WIRED_S390_NETTYPE, priv->s390_nettype, NULL);
g_hash_table_iter_init (&iter, priv->s390_options);
while (g_hash_table_iter_next (&iter, &key, &value)) {
nm_setting_wired_add_s390_option (s_wired, (const char *) key, (const char *) value);
}
_nm_setting_wired_clear_s390_options (s_wired);
g_hash_table_iter_init (&iter, priv->s390_options);
while (g_hash_table_iter_next (&iter, &key, &value))
nm_setting_wired_add_s390_option (s_wired, (const char *) key, (const char *) value);
}
static void

View file

@ -4512,7 +4512,7 @@ make_wired_setting (shvarFile *ifcfg,
gs_free const char **options = NULL;
gsize i;
options = nm_utils_strsplit_set_with_empty (value, " ");
options = nm_utils_escaped_tokens_split (value, NM_ASCII_SPACES);
for (i = 0; options && options[i]; i++) {
const char *line = options[i];
const char *equals;

View file

@ -1118,14 +1118,22 @@ write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
nm_setting_wired_get_s390_option (s_wired, i, &s390_key, &s390_val);
/* portname is handled separately */
if (!strcmp (s390_key, "portname") || !strcmp (s390_key, "ctcprot"))
if (NM_IN_STRSET (s390_key, "portname", "ctcprot"))
continue;
if (strchr (s390_key, '=')) {
/* this key cannot be expressed. But after all, it's not valid anyway
* and the connection shouldn't even verify. */
continue;
}
if (!tmp)
tmp = g_string_sized_new (30);
else
g_string_append_c (tmp, ' ');
g_string_append_printf (tmp, "%s=%s", s390_key, s390_val);
nm_utils_escaped_tokens_escape_gstr (s390_key, NM_ASCII_SPACES, tmp);
g_string_append_c (tmp, '=');
nm_utils_escaped_tokens_escape_gstr (s390_val, NM_ASCII_SPACES, tmp);
}
if (tmp)
svSetValueStr (ifcfg, "OPTIONS", tmp->str);