core: merge branch 'th/no-auto-default-by-ifname'

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/merge_requests/206
This commit is contained in:
Thomas Haller 2019-07-25 11:38:22 +02:00
commit 3c003e0ea4
12 changed files with 179 additions and 93 deletions

View file

@ -4660,7 +4660,7 @@ nm_utils_is_valid_iface_name_utf8safe (const char *utf8safe_name)
/**
* nm_utils_is_valid_iface_name:
* @name: Name of interface
* @name: (allow-none): Name of interface
* @error: location to store the error occurring, or %NULL to ignore
*
* Validate the network interface name.
@ -4669,13 +4669,20 @@ nm_utils_is_valid_iface_name_utf8safe (const char *utf8safe_name)
* function in net/core/dev.c.
*
* Returns: %TRUE if interface name is valid, otherwise %FALSE is returned.
*
* Before 1.20, this function did not accept %NULL as @name argument. If you
* want to run against older versions of libnm, don't pass %NULL.
*/
gboolean
nm_utils_is_valid_iface_name (const char *name, GError **error)
{
int i;
g_return_val_if_fail (name, FALSE);
if (!name) {
g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
_("interface name is missing"));
return FALSE;
}
if (name[0] == '\0') {
g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
@ -4712,13 +4719,16 @@ nm_utils_is_valid_iface_name (const char *name, GError **error)
/**
* nm_utils_iface_valid_name:
* @name: Name of interface
* @name: (allow-none): Name of interface
*
* Validate the network interface name.
*
* Deprecated: 1.6: use nm_utils_is_valid_iface_name() instead, with better error reporting.
*
* Returns: %TRUE if interface name is valid, otherwise %FALSE is returned.
*
* Before 1.20, this function did not accept %NULL as @name argument. If you
* want to run against older versions of libnm, don't pass %NULL.
*/
gboolean
nm_utils_iface_valid_name (const char *name)

View file

@ -806,6 +806,15 @@ _nm_utils_ascii_str_to_uint64 (const char *str, guint base, guint64 min, guint64
/*****************************************************************************/
int
nm_strcmp_with_data (gconstpointer a, gconstpointer b, gpointer user_data)
{
const char *s1 = a;
const char *s2 = b;
return strcmp (s1, s2);
}
/* like nm_strcmp_p(), suitable for g_ptr_array_sort_with_data().
* g_ptr_array_sort() just casts nm_strcmp_p() to a function of different
* signature. I guess, in glib there are knowledgeable people that ensure
@ -822,6 +831,15 @@ nm_strcmp_p_with_data (gconstpointer a, gconstpointer b, gpointer user_data)
return strcmp (s1, s2);
}
int
nm_strcmp0_p_with_data (gconstpointer a, gconstpointer b, gpointer user_data)
{
const char *s1 = *((const char **) a);
const char *s2 = *((const char **) b);
return nm_strcmp0 (s1, s2);
}
int
nm_cmp_uint32_p_with_data (gconstpointer p_a, gconstpointer p_b, gpointer user_data)
{
@ -1346,6 +1364,8 @@ _nm_utils_strv_cleanup (char **strv,
return strv;
if (strip_whitespace) {
/* we only modify the strings pointed to by @strv if @strip_whitespace is
* requested. Otherwise, the strings themselves are untouched. */
for (i = 0; strv[i]; i++)
g_strstrip (strv[i]);
}
@ -2690,8 +2710,8 @@ fail:
* @len: the number of elements in strv. If negative,
* strv must be a NULL terminated array and the length
* will be calculated first. If @len is a positive
* number, all first @len elements in @strv must be
* non-NULL, valid strings.
* number, @strv is allowed to contain %NULL strings
* too.
*
* Ascending sort of the array @strv inplace, using plain strcmp() string
* comparison.
@ -2699,9 +2719,16 @@ fail:
void
_nm_utils_strv_sort (const char **strv, gssize len)
{
GCompareDataFunc cmp;
gsize l;
l = len < 0 ? (gsize) NM_PTRARRAY_LEN (strv) : (gsize) len;
if (len < 0) {
l = NM_PTRARRAY_LEN (strv);
cmp = nm_strcmp_p_with_data;
} else {
l = len;
cmp = nm_strcmp0_p_with_data;
}
if (l <= 1)
return;
@ -2711,7 +2738,7 @@ _nm_utils_strv_sort (const char **strv, gssize len)
g_qsort_with_data (strv,
l,
sizeof (const char *),
nm_strcmp_p_with_data,
cmp,
NULL);
}

View file

@ -918,7 +918,9 @@ nm_utf8_collate0 (const char *a, const char *b)
return g_utf8_collate (a, b);
}
int nm_strcmp_with_data (gconstpointer a, gconstpointer b, gpointer user_data);
int nm_strcmp_p_with_data (gconstpointer a, gconstpointer b, gpointer user_data);
int nm_strcmp0_p_with_data (gconstpointer a, gconstpointer b, gpointer user_data);
int nm_cmp_uint32_p_with_data (gconstpointer p_a, gconstpointer p_b, gpointer user_data);
int nm_cmp_int2ptr_p_with_data (gconstpointer p_a, gconstpointer p_b, gpointer user_data);

View file

@ -4796,9 +4796,6 @@ nm_device_new_default_connection (NMDevice *self)
if (!NM_DEVICE_GET_CLASS (self)->new_default_connection)
return NULL;
if (nm_config_get_no_auto_default_for_device (nm_config_get (), self))
return NULL;
connection = NM_DEVICE_GET_CLASS (self)->new_default_connection (self);
if (!connection)
return NULL;

View file

@ -1503,16 +1503,6 @@ _match_section_infos_construct (GKeyFile *keyfile, const char *prefix)
/*****************************************************************************/
static gboolean
_slist_str_equals (GSList *a, GSList *b)
{
while (a && b && g_strcmp0 (a->data, b->data) == 0) {
a = a->next;
b = b->next;
}
return !a && !b;
}
NMConfigChangeFlags
nm_config_data_diff (NMConfigData *old_data, NMConfigData *new_data)
{
@ -1541,8 +1531,8 @@ nm_config_data_diff (NMConfigData *old_data, NMConfigData *new_data)
|| g_strcmp0 (nm_config_data_get_connectivity_response (old_data), nm_config_data_get_connectivity_response (new_data)))
changes |= NM_CONFIG_CHANGE_CONNECTIVITY;
if ( !_slist_str_equals (priv_old->no_auto_default.specs, priv_new->no_auto_default.specs)
|| !_slist_str_equals (priv_old->no_auto_default.specs_config, priv_new->no_auto_default.specs_config))
if ( nm_utils_g_slist_strlist_cmp (priv_old->no_auto_default.specs, priv_new->no_auto_default.specs) != 0
|| nm_utils_g_slist_strlist_cmp (priv_old->no_auto_default.specs_config, priv_new->no_auto_default.specs_config) != 0)
changes |= NM_CONFIG_CHANGE_NO_AUTO_DEFAULT;
if (g_strcmp0 (nm_config_data_get_dns_mode (old_data), nm_config_data_get_dns_mode (new_data)))
@ -1633,22 +1623,47 @@ set_property (GObject *object,
case PROP_NO_AUTO_DEFAULT:
/* construct-only */
{
char **value_arr = g_value_get_boxed (value);
guint i, j = 0;
const char *const*value_arr_orig = g_value_get_boxed (value);
gs_free const char **value_arr = NULL;
GSList *specs = NULL;
gsize i, j;
gsize len;
priv->no_auto_default.arr = g_new (char *, g_strv_length (value_arr) + 1);
priv->no_auto_default.specs = NULL;
len = NM_PTRARRAY_LEN (value_arr_orig);
for (i = 0; value_arr && value_arr[i]; i++) {
if ( *value_arr[i]
&& nm_utils_hwaddr_valid (value_arr[i], -1)
&& nm_utils_strv_find_first (value_arr, i, value_arr[i]) < 0) {
priv->no_auto_default.arr[j++] = g_strdup (value_arr[i]);
priv->no_auto_default.specs = g_slist_prepend (priv->no_auto_default.specs, g_strdup_printf ("mac:%s", value_arr[i]));
/* sort entries, remove duplicates and empty words. */
value_arr = len == 0
? NULL
: nm_memdup (value_arr_orig, sizeof (const char *) * (len + 1));
nm_utils_strv_sort (value_arr, len);
_nm_utils_strv_cleanup ((char **) value_arr, FALSE, TRUE, TRUE);
len = NM_PTRARRAY_LEN (value_arr);
j = 0;
for (i = 0; i < len; i++) {
const char *s = value_arr[i];
gboolean is_mac;
char *spec;
if (NM_STR_HAS_PREFIX (s, NM_MATCH_SPEC_INTERFACE_NAME_TAG"="))
is_mac = FALSE;
else if (nm_utils_hwaddr_valid (s, -1))
is_mac = TRUE;
else {
/* we drop all lines that we don't understand. */
continue;
}
value_arr[j++] = s;
spec = is_mac
? g_strdup_printf (NM_MATCH_SPEC_MAC_TAG"%s", s)
: g_strdup (s);
specs = g_slist_prepend (specs, spec);
}
priv->no_auto_default.arr[j++] = NULL;
priv->no_auto_default.specs = g_slist_reverse (priv->no_auto_default.specs);
priv->no_auto_default.arr = nm_utils_strv_dup (value_arr, j);
priv->no_auto_default.specs = g_slist_reverse (specs);
}
break;
default:

View file

@ -349,47 +349,44 @@ nm_config_get_first_start (NMConfig *config)
static char **
no_auto_default_from_file (const char *no_auto_default_file)
{
GPtrArray *no_auto_default_new;
char **list;
guint i;
char *data;
no_auto_default_new = g_ptr_array_new ();
gs_free char *data = NULL;
const char **list = NULL;
gsize i;
if ( no_auto_default_file
&& g_file_get_contents (no_auto_default_file, &data, NULL, NULL)) {
list = g_strsplit (data, "\n", -1);
for (i = 0; list[i]; i++) {
if ( *list[i]
&& nm_utils_hwaddr_valid (list[i], -1)
&& nm_utils_strv_find_first (list, i, list[i]) < 0)
g_ptr_array_add (no_auto_default_new, list[i]);
else
g_free (list[i]);
}
g_free (list);
g_free (data);
&& g_file_get_contents (no_auto_default_file, &data, NULL, NULL))
list = nm_utils_strsplit_set (data, "\n");
if (list) {
for (i = 0; list[i]; i++)
list[i] = nm_utils_str_utf8safe_unescape_cp (list[i]);
}
g_ptr_array_add (no_auto_default_new, NULL);
return (char **) g_ptr_array_free (no_auto_default_new, FALSE);
/* The returned buffer here is not at all compact. That means, it has additional
* memory allocations and is larger than needed. That means, you should not keep
* this result around, only process it further and free it. */
return (char **) list;
}
static gboolean
no_auto_default_to_file (const char *no_auto_default_file, const char *const*no_auto_default, GError **error)
{
GString *data;
gboolean success;
guint i;
nm_auto_free_gstring GString *data = NULL;
gsize i;
data = g_string_new ("");
for (i = 0; no_auto_default && no_auto_default[i]; i++) {
g_string_append (data, no_auto_default[i]);
gs_free char *s_to_free = NULL;
const char *s = no_auto_default[i];
s = nm_utils_str_utf8safe_escape (s,
NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL
| NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII,
&s_to_free);
g_string_append (data, s);
g_string_append_c (data, '\n');
}
success = g_file_set_contents (no_auto_default_file, data->str, data->len, error);
g_string_free (data, TRUE);
return success;
return g_file_set_contents (no_auto_default_file, data->str, data->len, error);
}
gboolean
@ -413,44 +410,76 @@ nm_config_set_no_auto_default_for_device (NMConfig *self, NMDevice *device)
NMConfigPrivate *priv;
GError *error = NULL;
NMConfigData *new_data = NULL;
gs_free char *spec_to_free = NULL;
const char *ifname;
const char *hw_address;
const char *spec;
const char *const*no_auto_default_current;
GPtrArray *no_auto_default_new = NULL;
guint i;
gs_free const char **no_auto_default_new = NULL;
gboolean is_fake;
gsize len;
gssize idx;
g_return_if_fail (NM_IS_CONFIG (self));
g_return_if_fail (NM_IS_DEVICE (device));
priv = NM_CONFIG_GET_PRIVATE (self);
hw_address = nm_device_get_permanent_hw_address (device);
if (!hw_address)
hw_address = nm_device_get_permanent_hw_address_full (device, TRUE, &is_fake);
if (!hw_address) {
/* No MAC address, not even a fake one. We don't do anything for this device. */
return;
}
if (is_fake) {
/* A fake MAC address, no point in storing it to the file.
* Also, nm_match_spec_device() would ignore fake MAC addresses.
*
* Instead, try the interface-name... */
ifname = nm_device_get_ip_iface (device);
if (!nm_utils_is_valid_iface_name (ifname, NULL))
return;
spec_to_free = g_strdup_printf (NM_MATCH_SPEC_INTERFACE_NAME_TAG"=%s", ifname);
spec = spec_to_free;
} else
spec = hw_address;
no_auto_default_current = nm_config_data_get_no_auto_default (priv->config_data);
if (nm_utils_strv_find_first ((char **) no_auto_default_current, -1, hw_address) >= 0) {
/* @hw_address is already blocked. We don't have to update our in-memory representation.
len = NM_PTRARRAY_LEN (no_auto_default_current);
idx = nm_utils_ptrarray_find_binary_search ((gconstpointer *) no_auto_default_current,
len,
spec,
nm_strcmp_with_data,
NULL,
NULL,
NULL);
if (idx >= 0) {
/* @spec is already blocked. We don't have to update our in-memory representation.
* Maybe we should write to no_auto_default_file anew, but let's save that too. */
return;
}
no_auto_default_new = g_ptr_array_new ();
for (i = 0; no_auto_default_current && no_auto_default_current[i]; i++)
g_ptr_array_add (no_auto_default_new, (char *) no_auto_default_current[i]);
g_ptr_array_add (no_auto_default_new, (char *) hw_address);
g_ptr_array_add (no_auto_default_new, NULL);
idx = ~idx;
if (!no_auto_default_to_file (priv->no_auto_default_file, (const char *const*) no_auto_default_new->pdata, &error)) {
no_auto_default_new = g_new (const char *, len + 2);
if (idx > 0)
memcpy (no_auto_default_new, no_auto_default_current, sizeof (const char *) * idx);
no_auto_default_new[idx] = spec;
if (idx < len)
memcpy (&no_auto_default_new[idx + 1], &no_auto_default_current[idx], sizeof (const char *) * (len - idx));
no_auto_default_new[len + 1] = NULL;
if (!no_auto_default_to_file (priv->no_auto_default_file, no_auto_default_new, &error)) {
_LOGW ("Could not update no-auto-default.state file: %s",
error->message);
g_error_free (error);
}
new_data = nm_config_data_new_update_no_auto_default (priv->config_data, (const char *const*) no_auto_default_new->pdata);
/* unref no_auto_default_set here. Note that _set_config_data() probably invalidates the content of the array. */
g_ptr_array_unref (no_auto_default_new);
new_data = nm_config_data_new_update_no_auto_default (priv->config_data, no_auto_default_new);
_set_config_data (self, new_data, NM_CONFIG_CHANGE_CAUSE_NO_AUTO_DEFAULT);
}

View file

@ -1158,13 +1158,10 @@ nm_utils_read_link_absolute (const char *link_file, GError **error)
/*****************************************************************************/
#define MAC_TAG "mac:"
#define INTERFACE_NAME_TAG "interface-name:"
#define DEVICE_TYPE_TAG "type:"
#define DRIVER_TAG "driver:"
#define SUBCHAN_TAG "s390-subchannels:"
#define DHCP_PLUGIN_TAG "dhcp-plugin:"
#define EXCEPT_TAG "except:"
#define DEVICE_TYPE_TAG "type:"
#define DRIVER_TAG "driver:"
#define DHCP_PLUGIN_TAG "dhcp-plugin:"
#define EXCEPT_TAG "except:"
#define MATCH_TAG_CONFIG_NM_VERSION "nm-version:"
#define MATCH_TAG_CONFIG_NM_VERSION_MIN "nm-version-min:"
#define MATCH_TAG_CONFIG_NM_VERSION_MAX "nm-version-max:"
@ -1363,10 +1360,10 @@ match_device_eval (const char *spec_str,
&& nm_streq (spec_str, match_data->device_type);
}
if (_MATCH_CHECK (spec_str, MAC_TAG))
if (_MATCH_CHECK (spec_str, NM_MATCH_SPEC_MAC_TAG))
return match_device_hwaddr_eval (spec_str, match_data);
if (_MATCH_CHECK (spec_str, INTERFACE_NAME_TAG)) {
if (_MATCH_CHECK (spec_str, NM_MATCH_SPEC_INTERFACE_NAME_TAG)) {
gboolean use_pattern = FALSE;
if (spec_str[0] == '=')
@ -1418,7 +1415,7 @@ match_device_eval (const char *spec_str,
match_data->driver_version ?: "");
}
if (_MATCH_CHECK (spec_str, SUBCHAN_TAG))
if (_MATCH_CHECK (spec_str, NM_MATCH_SPEC_S390_SUBCHANNELS_TAG))
return match_data_s390_subchannels_eval (spec_str, match_data);
if (_MATCH_CHECK (spec_str, DHCP_PLUGIN_TAG))

View file

@ -216,6 +216,10 @@ const char *nm_utils_find_helper (const char *progname,
char *nm_utils_read_link_absolute (const char *link_file, GError **error);
#define NM_MATCH_SPEC_MAC_TAG "mac:"
#define NM_MATCH_SPEC_S390_SUBCHANNELS_TAG "s390-subchannels:"
#define NM_MATCH_SPEC_INTERFACE_NAME_TAG "interface-name:"
typedef enum {
NM_MATCH_SPEC_NO_MATCH = 0,
NM_MATCH_SPEC_MATCH = 1,

View file

@ -2907,6 +2907,7 @@ static void
device_realized (NMDevice *device, GParamSpec *pspec, NMSettings *self)
{
gs_unref_object NMConnection *connection = NULL;
NMSettingsPrivate *priv;
NMSettingsConnection *added;
GError *error = NULL;
@ -2917,12 +2918,15 @@ device_realized (NMDevice *device, GParamSpec *pspec, NMSettings *self)
G_CALLBACK (device_realized),
self);
priv = NM_SETTINGS_GET_PRIVATE (self);
/* If the device isn't managed or it already has a default wired connection,
* ignore it.
*/
if ( !nm_device_get_managed (device, FALSE)
|| g_object_get_qdata (G_OBJECT (device), _default_wired_connection_quark ())
|| have_connection_for_device (self, device))
|| have_connection_for_device (self, device)
|| nm_config_get_no_auto_default_for_device (priv->config, device))
return;
connection = nm_device_new_default_connection (device);

View file

@ -5630,21 +5630,21 @@ create_unhandled_connection (const char *filename, shvarFile *ifcfg,
if (v) {
gs_free char *lower = g_ascii_strdown (v, -1);
*out_spec = g_strdup_printf ("%s:mac:%s", type, lower);
*out_spec = g_strdup_printf ("%s:"NM_MATCH_SPEC_MAC_TAG"%s", type, lower);
return connection;
}
nm_clear_g_free (&value);
v = svGetValueStr (ifcfg, "SUBCHANNELS", &value);
if (v) {
*out_spec = g_strdup_printf ("%s:s390-subchannels:%s", type, v);
*out_spec = g_strdup_printf ("%s:"NM_MATCH_SPEC_S390_SUBCHANNELS_TAG"%s", type, v);
return connection;
}
nm_clear_g_free (&value);
v = svGetValueStr (ifcfg, "DEVICE", &value);
if (v) {
*out_spec = g_strdup_printf ("%s:interface-name:%s", type, v);
*out_spec = g_strdup_printf ("%s:"NM_MATCH_SPEC_INTERFACE_NAME_TAG"=%s", type, v);
return connection;
}

View file

@ -721,7 +721,7 @@ test_read_unmanaged_unrecognized (void)
connection = _connection_from_file (TEST_IFCFG_DIR"/ifcfg-test-nm-controlled-unrecognized",
NULL, NULL,
&unhandled_spec);
g_assert_cmpstr (unhandled_spec, ==, "unmanaged:interface-name:ipoac0");
g_assert_cmpstr (unhandled_spec, ==, "unmanaged:interface-name:=ipoac0");
/* ===== CONNECTION SETTING ===== */
s_con = nm_connection_get_setting_connection (connection);

View file

@ -25,6 +25,7 @@
#include "nms-ifupdown-plugin.h"
#include "nm-core-internal.h"
#include "nm-core-utils.h"
#include "nm-config.h"
#include "settings/nm-settings-plugin.h"
#include "settings/nm-settings-storage.h"
@ -208,7 +209,7 @@ _unmanaged_specs (GHashTable *eni_ifaces)
keys = nm_utils_strdict_get_keys (eni_ifaces, TRUE, &len);
for (i = len; i > 0; ) {
i--;
specs = g_slist_prepend (specs, g_strdup_printf ("interface-name:=%s", keys[i]));
specs = g_slist_prepend (specs, g_strdup_printf (NM_MATCH_SPEC_INTERFACE_NAME_TAG"=%s", keys[i]));
}
return specs;
}