core: merge branch 'th/spec-match-bgo743411'

https://bugzilla.gnome.org/show_bug.cgi?id=743411
This commit is contained in:
Thomas Haller
2015-02-24 10:58:47 +01:00
10 changed files with 431 additions and 135 deletions

View File

@@ -148,7 +148,7 @@ Copyright 2010 - 2014 Red Hat, Inc.
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><varname>no-auto-default</varname></term> <term><varname>no-auto-default</varname></term>
<listitem><para>Comma-separated list of devices for which <listitem><para>Specify devices for which
NetworkManager shouldn't create default wired connection NetworkManager shouldn't create default wired connection
(Auto eth0). By default, NetworkManager creates a temporary (Auto eth0). By default, NetworkManager creates a temporary
wired connection for any Ethernet device that is managed and wired connection for any Ethernet device that is managed and
@@ -162,11 +162,15 @@ Copyright 2010 - 2014 Red Hat, Inc.
<filename>/var/run/NetworkManager/no-auto-default.state</filename> <filename>/var/run/NetworkManager/no-auto-default.state</filename>
to prevent creating the default connection for that device to prevent creating the default connection for that device
again.</para> again.</para>
<para>See <xref linkend="device-spec"/> for the syntax how to
specify a device.
</para>
<para> <para>
Example:
<programlisting> <programlisting>
no-auto-default=00:22:68:5c:5d:c4,00:1e:65:ff:aa:ee no-auto-default=00:22:68:5c:5d:c4,00:1e:65:ff:aa:ee
no-auto-default=eth0,eth1 no-auto-default=eth0,eth1
no-auto-default=* no-auto-default=*
</programlisting> </programlisting>
</para> </para>
</listitem> </listitem>
@@ -176,8 +180,8 @@ Copyright 2010 - 2014 Red Hat, Inc.
<term><varname>ignore-carrier</varname></term> <term><varname>ignore-carrier</varname></term>
<listitem> <listitem>
<para> <para>
Comma-separated list of devices for which NetworkManager Specify devices for which NetworkManager will (partially)
will (partially) ignore the carrier state. Normally, for ignore the carrier state. Normally, for
device types that support carrier-detect, such as Ethernet device types that support carrier-detect, such as Ethernet
and InfiniBand, NetworkManager will only allow a and InfiniBand, NetworkManager will only allow a
connection to be activated on the device if carrier is connection to be activated on the device if carrier is
@@ -193,15 +197,14 @@ Copyright 2010 - 2014 Red Hat, Inc.
connection (whether static or dynamic) to remain active on connection (whether static or dynamic) to remain active on
the device when carrier is lost. the device when carrier is lost.
</para> </para>
<para>
May have the special value <literal>*</literal> to apply
to all devices.
</para>
<para> <para>
Note that the "carrier" property of NMDevices and device D-Bus Note that the "carrier" property of NMDevices and device D-Bus
interfaces will still reflect the actual device state; it's just interfaces will still reflect the actual device state; it's just
that NetworkManager will not make use of that information. that NetworkManager will not make use of that information.
</para> </para>
<para>See <xref linkend="device-spec"/> for the syntax how to
specify a device.
</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@@ -279,17 +282,11 @@ Copyright 2010 - 2014 Red Hat, Inc.
<varlistentry> <varlistentry>
<term><varname>unmanaged-devices</varname></term> <term><varname>unmanaged-devices</varname></term>
<listitem><para>Set devices that should be ignored by <listitem><para>Set devices that should be ignored by
NetworkManager when using the <literal>keyfile</literal> NetworkManager.
plugin. Devices are specified in the following </para>
format:</para> <para>See <xref linkend="device-spec"/> for the syntax how to
<para><literal>mac:&lt;hwaddr&gt;</literal> or specify a device.
<literal>interface-name:&lt;ifname&gt;</literal>. Here </para>
<literal>hwaddr</literal> is the MAC address of the device
to be ignored, in hex-digits-and-colons notation.
<literal>ifname</literal> is the interface name of the
ignored device.</para>
<para>Multiple entries are separated with semicolons. No
spaces are allowed in the value.</para>
<para> <para>
Example: Example:
<programlisting> <programlisting>
@@ -545,6 +542,77 @@ unmanaged-devices=mac:00:22:68:1c:59:b1;mac:00:1E:65:30:D1:C4;interface-name:eth
</variablelist> </variablelist>
</refsect1> </refsect1>
<refsect1>
<title>Appendix</title>
<refsect2 id="device-spec">
<title>Device List Format</title>
<para>
The configuration options <literal>main.no-auto-default</literal>, <literal>main.ignore-carrier</literal>,
and <literal>keyfile.unmanaged-devices</literal> select devices based on a list of matchings.
Devices can be specified using the following format:
</para>
<para>
<variablelist>
<varlistentry>
<term>*</term>
<listitem><para>Matches every device.</para></listitem>
</varlistentry>
<varlistentry>
<term>IFNAME</term>
<listitem><para>Case sensitive match of interface name of the device. Globbing is not supported.</para></listitem>
</varlistentry>
<varlistentry>
<term>HWADDR</term>
<listitem><para>Match the MAC address of the device. Globbing is not supported</para></listitem>
</varlistentry>
<varlistentry>
<term>interface-name:IFNAME</term>
<term>interface-name:~IFNAME</term>
<listitem><para>Case sensitive match of interface name of the device. Simple globbing is supported with
<literal>*</literal> and <literal>?</literal>. Ranges and escaping is not supported.</para></listitem>
</varlistentry>
<varlistentry>
<term>interface-name:=IFNAME</term>
<listitem><para>Case sensitive match of interface name of the device. Globbing is disabled and <literal>IFNAME</literal>
is taken literally.</para></listitem>
</varlistentry>
<varlistentry>
<term>mac:HWADDR</term>
<listitem><para>Match the MAC address of the device. Globbing is not supported</para></listitem>
</varlistentry>
<varlistentry>
<term>s390-subchannels:HWADDR</term>
<listitem><para>Match the device based on the subchannel address. Globbing is not supported</para></listitem>
</varlistentry>
<varlistentry>
<term>except:SPEC</term>
<listitem><para>Negative match of a device. <literal>SPEC</literal> must be explicitly qualified with
a prefix such as <literal>interface-name:</literal>. A negative match has higher priority then the positive
matches above.</para></listitem>
</varlistentry>
<varlistentry>
<term>SPEC[,;]SPEC</term>
<listitem><para>Multiple specs can be concatenated with comman or semicolon. The order does not matter as
matches are either positive (inclusive) or negative, with negative matches having higher priority.</para>
<para>Backslash is supported to escape the separators ';' and ',', and to express special
characters such as newline ('\n'), tabulator ('\t'), whitespace ('\s') and backslash ('\\'). The globbing of
interface names cannot be escaped. Whitespace is taken literally so usually the specs will be concatenated
without spaces.</para></listitem>
</varlistentry>
</variablelist>
</para>
<para>
Example:
<programlisting>
interface-name:em4
mac:00:22:68:1c:59:b1;mac:00:1E:65:30:D1:C4;interface-name:eth2
interface-name:vboxnet*,except:interface-name:vboxnet2
*,except:mac:00:22:68:1c:59:b1
</programlisting>
</para>
</refsect2>
</refsect1>
<refsect1> <refsect1>
<title>See Also</title> <title>See Also</title>
<para> <para>

View File

@@ -864,55 +864,99 @@ nm_utils_find_helper(const char *progname, const char *try_first, GError **error
/******************************************************************************************/ /******************************************************************************************/
gboolean #define MAC_TAG "mac:"
nm_match_spec_string (const GSList *specs, const char *match) #define INTERFACE_NAME_TAG "interface-name:"
#define SUBCHAN_TAG "s390-subchannels:"
#define EXCEPT_TAG "except:"
static const char *
_match_except (const char *spec_str, gboolean *out_except)
{ {
const GSList *iter; if (!g_ascii_strncasecmp (spec_str, EXCEPT_TAG, STRLEN (EXCEPT_TAG))) {
spec_str += STRLEN (EXCEPT_TAG);
for (iter = specs; iter; iter = g_slist_next (iter)) { *out_except = TRUE;
if (!g_ascii_strcasecmp ((const char *) iter->data, match)) } else
return TRUE; *out_except = FALSE;
} return spec_str;
return FALSE;
} }
gboolean NMMatchSpecMatchType
nm_match_spec_hwaddr (const GSList *specs, const char *hwaddr) nm_match_spec_hwaddr (const GSList *specs, const char *hwaddr)
{ {
const GSList *iter; const GSList *iter;
NMMatchSpecMatchType match = NM_MATCH_SPEC_NO_MATCH;
g_return_val_if_fail (hwaddr != NULL, FALSE); g_return_val_if_fail (hwaddr != NULL, NM_MATCH_SPEC_NO_MATCH);
for (iter = specs; iter; iter = g_slist_next (iter)) { for (iter = specs; iter; iter = g_slist_next (iter)) {
const char *spec_str = iter->data; const char *spec_str = iter->data;
gboolean except;
if ( !g_ascii_strncasecmp (spec_str, "mac:", 4) if (!spec_str || !*spec_str)
&& nm_utils_hwaddr_matches (spec_str + 4, -1, hwaddr, -1)) continue;
return TRUE;
if (nm_utils_hwaddr_matches (spec_str, -1, hwaddr, -1)) spec_str = _match_except (spec_str, &except);
return TRUE;
if ( !g_ascii_strncasecmp (spec_str, INTERFACE_NAME_TAG, STRLEN (INTERFACE_NAME_TAG))
|| !g_ascii_strncasecmp (spec_str, SUBCHAN_TAG, STRLEN (SUBCHAN_TAG)))
continue;
if (!g_ascii_strncasecmp (spec_str, MAC_TAG, STRLEN (MAC_TAG)))
spec_str += STRLEN (MAC_TAG);
else if (except)
continue;
if (nm_utils_hwaddr_matches (spec_str, -1, hwaddr, -1)) {
if (except)
return NM_MATCH_SPEC_NEG_MATCH;
match = NM_MATCH_SPEC_MATCH;
}
} }
return match;
return FALSE;
} }
gboolean NMMatchSpecMatchType
nm_match_spec_interface_name (const GSList *specs, const char *interface_name) nm_match_spec_interface_name (const GSList *specs, const char *interface_name)
{ {
char *iface_match; const GSList *iter;
gboolean matched; NMMatchSpecMatchType match = NM_MATCH_SPEC_NO_MATCH;
g_return_val_if_fail (interface_name != NULL, FALSE); g_return_val_if_fail (interface_name != NULL, NM_MATCH_SPEC_NO_MATCH);
if (nm_match_spec_string (specs, interface_name)) for (iter = specs; iter; iter = g_slist_next (iter)) {
return TRUE; const char *spec_str = iter->data;
gboolean use_pattern = FALSE;
gboolean except;
iface_match = g_strdup_printf ("interface-name:%s", interface_name); if (!spec_str || !*spec_str)
matched = nm_match_spec_string (specs, iface_match); continue;
g_free (iface_match);
return matched; spec_str = _match_except (spec_str, &except);
if ( !g_ascii_strncasecmp (spec_str, MAC_TAG, STRLEN (MAC_TAG))
|| !g_ascii_strncasecmp (spec_str, SUBCHAN_TAG, STRLEN (SUBCHAN_TAG)))
continue;
if (!g_ascii_strncasecmp (spec_str, INTERFACE_NAME_TAG, STRLEN (INTERFACE_NAME_TAG))) {
spec_str += STRLEN (INTERFACE_NAME_TAG);
if (spec_str[0] == '=')
spec_str += 1;
else {
if (spec_str[0] == '~')
spec_str += 1;
use_pattern=TRUE;
}
} else if (except)
continue;
if ( !strcmp (spec_str, interface_name)
|| (use_pattern && g_pattern_match_simple (spec_str, interface_name))) {
if (except)
return NM_MATCH_SPEC_NEG_MATCH;
match = NM_MATCH_SPEC_MATCH;
}
}
return match;
} }
#define BUFSIZE 10 #define BUFSIZE 10
@@ -981,33 +1025,108 @@ parse_subchannels (const char *subchannels, guint32 *a, guint32 *b, guint32 *c)
return TRUE; return TRUE;
} }
#define SUBCHAN_TAG "s390-subchannels:" NMMatchSpecMatchType
gboolean
nm_match_spec_s390_subchannels (const GSList *specs, const char *subchannels) nm_match_spec_s390_subchannels (const GSList *specs, const char *subchannels)
{ {
const GSList *iter; const GSList *iter;
guint32 a = 0, b = 0, c = 0; guint32 a = 0, b = 0, c = 0;
guint32 spec_a = 0, spec_b = 0, spec_c = 0; guint32 spec_a = 0, spec_b = 0, spec_c = 0;
NMMatchSpecMatchType match = NM_MATCH_SPEC_NO_MATCH;
g_return_val_if_fail (subchannels != NULL, FALSE); g_return_val_if_fail (subchannels != NULL, NM_MATCH_SPEC_NO_MATCH);
if (!parse_subchannels (subchannels, &a, &b, &c)) if (!parse_subchannels (subchannels, &a, &b, &c))
return FALSE; return NM_MATCH_SPEC_NO_MATCH;
for (iter = specs; iter; iter = g_slist_next (iter)) { for (iter = specs; iter; iter = g_slist_next (iter)) {
const char *spec = iter->data; const char *spec_str = iter->data;
gboolean except;
if (!strncmp (spec, SUBCHAN_TAG, strlen (SUBCHAN_TAG))) { if (!spec_str || !*spec_str)
spec += strlen (SUBCHAN_TAG); continue;
if (parse_subchannels (spec, &spec_a, &spec_b, &spec_c)) {
if (a == spec_a && b == spec_b && c == spec_c) spec_str = _match_except (spec_str, &except);
return TRUE;
if (!g_ascii_strncasecmp (spec_str, SUBCHAN_TAG, STRLEN (SUBCHAN_TAG))) {
spec_str += STRLEN (SUBCHAN_TAG);
if (parse_subchannels (spec_str, &spec_a, &spec_b, &spec_c)) {
if (a == spec_a && b == spec_b && c == spec_c) {
if (except)
return NM_MATCH_SPEC_NEG_MATCH;
match = NM_MATCH_SPEC_MATCH;
}
} }
} }
} }
return match;
}
return FALSE; GSList *
nm_match_spec_split (const char *value)
{
char *string_value, *p, *q0, *q;
GSList *pieces = NULL;
if (!value || !*value)
return NULL;
/* Copied from glibs g_key_file_parse_value_as_string() function
* and adjusted. */
string_value = g_new (gchar, strlen (value) + 1);
p = (gchar *) value;
q0 = q = string_value;
while (*p) {
if (*p == '\\') {
p++;
switch (*p) {
case 's':
*q = ' ';
break;
case 'n':
*q = '\n';
break;
case 't':
*q = '\t';
break;
case 'r':
*q = '\r';
break;
case '\\':
*q = '\\';
break;
case '\0':
break;
default:
if (NM_IN_SET (*p, ',', ';'))
*q = *p;
else {
*q++ = '\\';
*q = *p;
}
break;
}
} else {
*q = *p;
if (NM_IN_SET (*p, ',', ';')) {
if (q0 < q)
pieces = g_slist_prepend (pieces, g_strndup (q0, q - q0));
q0 = q + 1;
}
}
if (*p == '\0')
break;
q++;
p++;
}
*q = '\0';
if (q0 < q)
pieces = g_slist_prepend (pieces, g_strndup (q0, q - q0));
g_free (string_value);
return g_slist_reverse (pieces);
} }
const char * const char *

View File

@@ -96,10 +96,16 @@ const char *nm_utils_find_helper (const char *progname,
const char *try_first, const char *try_first,
GError **error); GError **error);
gboolean nm_match_spec_string (const GSList *specs, const char *string); typedef enum {
gboolean nm_match_spec_hwaddr (const GSList *specs, const char *hwaddr); NM_MATCH_SPEC_NO_MATCH = 0,
gboolean nm_match_spec_s390_subchannels (const GSList *specs, const char *subchannels); NM_MATCH_SPEC_MATCH = 1,
gboolean nm_match_spec_interface_name (const GSList *specs, const char *interface_name); NM_MATCH_SPEC_NEG_MATCH = 2,
} NMMatchSpecMatchType;
NMMatchSpecMatchType nm_match_spec_hwaddr (const GSList *specs, const char *hwaddr);
NMMatchSpecMatchType nm_match_spec_s390_subchannels (const GSList *specs, const char *subchannels);
NMMatchSpecMatchType nm_match_spec_interface_name (const GSList *specs, const char *interface_name);
GSList *nm_match_spec_split (const char *value);
const char *nm_utils_get_shared_wifi_permission (NMConnection *connection); const char *nm_utils_get_shared_wifi_permission (NMConnection *connection);

View File

@@ -1495,15 +1495,19 @@ new_default_connection (NMDevice *self)
return connection; return connection;
} }
static gboolean static NMMatchSpecMatchType
spec_match_list (NMDevice *device, const GSList *specs) spec_match_list (NMDevice *device, const GSList *specs)
{ {
NMMatchSpecMatchType matched = NM_MATCH_SPEC_NO_MATCH, m;
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device); NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device);
if (priv->subchannels && nm_match_spec_s390_subchannels (specs, priv->subchannels)) if (priv->subchannels)
return TRUE; matched = nm_match_spec_s390_subchannels (specs, priv->subchannels);
if (matched != NM_MATCH_SPEC_NEG_MATCH) {
return NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->spec_match_list (device, specs); m = NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->spec_match_list (device, specs);
matched = MAX (matched, m);
}
return matched;
} }
static void static void

View File

@@ -8080,24 +8080,30 @@ nm_device_spec_match_list (NMDevice *self, const GSList *specs)
if (!specs) if (!specs)
return FALSE; return FALSE;
return NM_DEVICE_GET_CLASS (self)->spec_match_list (self, specs); return NM_DEVICE_GET_CLASS (self)->spec_match_list (self, specs) == NM_MATCH_SPEC_MATCH;
} }
static gboolean static NMMatchSpecMatchType
spec_match_list (NMDevice *self, const GSList *specs) spec_match_list (NMDevice *self, const GSList *specs)
{ {
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
gboolean matched = FALSE; NMMatchSpecMatchType matched = NM_MATCH_SPEC_NO_MATCH, m;
const GSList *iter;
if (nm_match_spec_string (specs, "*"))
return TRUE;
if (priv->hw_addr_len)
matched = nm_match_spec_hwaddr (specs, priv->hw_addr);
if (!matched)
matched = nm_match_spec_interface_name (specs, nm_device_get_iface (self));
for (iter = specs; iter; iter = g_slist_next (iter)) {
if (!strcmp ((const char *) iter->data, "*")) {
matched = NM_MATCH_SPEC_MATCH;
break;
}
}
if (priv->hw_addr_len) {
m = nm_match_spec_hwaddr (specs, priv->hw_addr);
matched = MAX (matched, m);
}
if (matched != NM_MATCH_SPEC_NEG_MATCH) {
m = nm_match_spec_interface_name (specs, nm_device_get_iface (self));
matched = MAX (matched, m);
}
return matched; return matched;
} }

View File

@@ -187,7 +187,7 @@ typedef struct {
/* Sync deactivating (in the DISCONNECTED phase) */ /* Sync deactivating (in the DISCONNECTED phase) */
void (* deactivate) (NMDevice *self); void (* deactivate) (NMDevice *self);
gboolean (* spec_match_list) (NMDevice *self, const GSList *specs); NMMatchSpecMatchType (* spec_match_list) (NMDevice *self, const GSList *specs);
/* Update the connection with currently configured L2 settings */ /* Update the connection with currently configured L2 settings */
void (* update_connection) (NMDevice *device, NMConnection *connection); void (* update_connection) (NMDevice *device, NMConnection *connection);

View File

@@ -32,6 +32,7 @@
#include "NetworkManagerUtils.h" #include "NetworkManagerUtils.h"
#include "gsystem-local-alloc.h" #include "gsystem-local-alloc.h"
#include "nm-enum-types.h" #include "nm-enum-types.h"
#include "nm-core-internal.h"
#include <gio/gio.h> #include <gio/gio.h>
#include <glib/gi18n.h> #include <glib/gi18n.h>
@@ -76,7 +77,7 @@ typedef struct {
char *debug; char *debug;
char **ignore_carrier; GSList *ignore_carrier;
gboolean configure_and_quit; gboolean configure_and_quit;
} NMConfigPrivate; } NMConfigPrivate;
@@ -237,21 +238,10 @@ nm_config_get_configure_and_quit (NMConfig *config)
gboolean gboolean
nm_config_get_ignore_carrier (NMConfig *config, NMDevice *device) nm_config_get_ignore_carrier (NMConfig *config, NMDevice *device)
{ {
NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (config); g_return_val_if_fail (NM_IS_CONFIG (config), FALSE);
GSList *specs = NULL; g_return_val_if_fail (NM_IS_DEVICE (device), FALSE);
int i;
gboolean match;
if (!priv->ignore_carrier) return nm_device_spec_match_list (device, NM_CONFIG_GET_PRIVATE (config)->ignore_carrier);
return FALSE;
for (i = 0; priv->ignore_carrier[i]; i++)
specs = g_slist_prepend (specs, priv->ignore_carrier[i]);
match = nm_device_spec_match_list (device, specs);
g_slist_free (specs);
return match;
} }
/************************************************************************/ /************************************************************************/
@@ -689,6 +679,15 @@ read_entire_config (const NMConfigCmdLineOptions *cli,
return keyfile; return keyfile;
} }
GSList *
nm_config_get_device_match_spec (const GKeyFile *keyfile, const char *group, const char *key)
{
gs_free char *value = NULL;
value = g_key_file_get_string ((GKeyFile *) keyfile, group, key, NULL);
return nm_match_spec_split (value);
}
/************************************************************************/ /************************************************************************/
void void
@@ -813,7 +812,8 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error)
char *config_main_file = NULL; char *config_main_file = NULL;
char *config_description = NULL; char *config_description = NULL;
char **no_auto_default; char **no_auto_default;
char **no_auto_default_orig; GSList *no_auto_default_orig_list;
GPtrArray *no_auto_default_orig;
if (priv->config_dir) { if (priv->config_dir) {
/* Object is already initialized. */ /* Object is already initialized. */
@@ -859,17 +859,22 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error)
priv->debug = g_key_file_get_value (keyfile, "main", "debug", NULL); priv->debug = g_key_file_get_value (keyfile, "main", "debug", NULL);
priv->ignore_carrier = g_key_file_get_string_list (keyfile, "main", "ignore-carrier", NULL, NULL); priv->ignore_carrier = nm_config_get_device_match_spec (keyfile, "main", "ignore-carrier");
priv->configure_and_quit = _get_bool_value (keyfile, "main", "configure-and-quit", FALSE); priv->configure_and_quit = _get_bool_value (keyfile, "main", "configure-and-quit", FALSE);
no_auto_default_orig = g_key_file_get_string_list (keyfile, "main", "no-auto-default", NULL, NULL); no_auto_default_orig_list = nm_config_get_device_match_spec (keyfile, "main", "no-auto-default");
no_auto_default = no_auto_default_merge_from_file (priv->no_auto_default_file, (const char *const *) no_auto_default_orig);
no_auto_default_orig = _nm_utils_copy_slist_to_array (no_auto_default_orig_list, NULL, NULL);
g_ptr_array_add (no_auto_default_orig, NULL);
no_auto_default = no_auto_default_merge_from_file (priv->no_auto_default_file, (const char *const *) no_auto_default_orig->pdata);
g_ptr_array_unref (no_auto_default_orig);
g_slist_free_full (no_auto_default_orig_list, g_free);
priv->config_data_orig = nm_config_data_new (config_main_file, config_description, (const char *const*) no_auto_default, keyfile); priv->config_data_orig = nm_config_data_new (config_main_file, config_description, (const char *const*) no_auto_default, keyfile);
g_strfreev (no_auto_default); g_strfreev (no_auto_default);
g_strfreev (no_auto_default_orig);
priv->config_data = g_object_ref (priv->config_data_orig); priv->config_data = g_object_ref (priv->config_data_orig);
@@ -910,7 +915,7 @@ finalize (GObject *gobject)
g_free (priv->log_level); g_free (priv->log_level);
g_free (priv->log_domains); g_free (priv->log_domains);
g_free (priv->debug); g_free (priv->debug);
g_strfreev (priv->ignore_carrier); g_slist_free_full (priv->ignore_carrier, g_free);
_nm_config_cmd_line_options_clear (&priv->cli); _nm_config_cmd_line_options_clear (&priv->cli);

View File

@@ -90,6 +90,7 @@ NMConfig *nm_config_setup (const NMConfigCmdLineOptions *cli, GError **error);
void nm_config_reload (NMConfig *config); void nm_config_reload (NMConfig *config);
GKeyFile *nm_config_create_keyfile (void); GKeyFile *nm_config_create_keyfile (void);
GSList *nm_config_get_device_match_spec (const GKeyFile *keyfile, const char *group, const char *key);
G_END_DECLS G_END_DECLS

View File

@@ -585,45 +585,19 @@ get_unmanaged_specs (NMSystemConfigInterface *config)
GKeyFile *key_file; GKeyFile *key_file;
GSList *specs = NULL; GSList *specs = NULL;
GError *error = NULL; GError *error = NULL;
char *str;
if (!priv->conf_file) if (!priv->conf_file)
return NULL; return NULL;
key_file = g_key_file_new (); key_file = nm_config_create_keyfile ();
if (!parse_key_file_allow_none (priv, key_file, &error)) if (parse_key_file_allow_none (priv, key_file, &error))
goto out; specs = nm_config_get_device_match_spec (key_file, "keyfile", "unmanaged-devices");
str = g_key_file_get_value (key_file, "keyfile", "unmanaged-devices", NULL);
if (str) {
char **udis;
int i;
udis = g_strsplit_set (str, ";,", -1);
g_free (str);
for (i = 0; udis[i] != NULL; i++) {
/* Verify unmanaged specification and add it to the list */
if (!strncmp (udis[i], "mac:", 4) && nm_utils_hwaddr_valid (udis[i] + 4, -1)) {
specs = g_slist_append (specs, udis[i]);
} else if (!strncmp (udis[i], "interface-name:", 15) && nm_utils_iface_valid_name (udis[i] + 15)) {
specs = g_slist_append (specs, udis[i]);
} else {
nm_log_warn (LOGD_SETTINGS, "keyfile: error in file '%s': invalid unmanaged-devices entry: '%s'", priv->conf_file, udis[i]);
g_free (udis[i]);
}
}
g_free (udis); /* Yes, g_free, not g_strfreev because we need the strings in the list */
}
out:
if (error) { if (error) {
nm_log_warn (LOGD_SETTINGS, "keyfile: error getting unmanaged specs: %s", error->message); nm_log_warn (LOGD_SETTINGS, "keyfile: error getting unmanaged specs: %s", error->message);
g_error_free (error); g_error_free (error);
} }
if (key_file) g_key_file_free (key_file);
g_key_file_free (key_file);
return specs; return specs;
} }

View File

@@ -774,6 +774,118 @@ test_nm_utils_uuid_generate_from_strings (void)
/*******************************************/ /*******************************************/
static const char *_test_match_spec_all[] = {
"e",
"em",
"em*",
"em\\",
"em\\*",
"em\\1",
"em\\11",
"em\\2",
"em1",
"em11",
"em2",
"=em*",
NULL
};
static gboolean
_test_match_spec_contains (const char **matches, const char *match)
{
guint i;
for (i = 0; matches && matches[i]; i++) {
if (strcmp (match, matches[i]) == 0)
return TRUE;
}
return FALSE;
}
static void
test_match_spec_ifname (const char *spec_str, const char **matches, const char **neg_matches)
{
const char *m;
GSList *specs, *specs_reverse = NULL;
guint i;
g_assert (spec_str);
specs = nm_match_spec_split (spec_str);
specs_reverse = g_slist_reverse (g_slist_copy (specs));
for (i = 0; matches && matches[i]; i++) {
g_assert (nm_match_spec_interface_name (specs, matches[i]) == NM_MATCH_SPEC_MATCH);
g_assert (nm_match_spec_interface_name (specs_reverse, matches[i]) == NM_MATCH_SPEC_MATCH);
}
for (i = 0; neg_matches && neg_matches[i]; i++) {
g_assert (nm_match_spec_interface_name (specs, neg_matches[i]) == NM_MATCH_SPEC_NEG_MATCH);
g_assert (nm_match_spec_interface_name (specs_reverse, neg_matches[i]) == NM_MATCH_SPEC_NEG_MATCH);
}
for (i = 0; (m = _test_match_spec_all[i]); i++) {
if (_test_match_spec_contains (matches, m))
continue;
if (_test_match_spec_contains (neg_matches, m))
continue;
g_assert (nm_match_spec_interface_name (specs, m) == NM_MATCH_SPEC_NO_MATCH);
g_assert (nm_match_spec_interface_name (specs_reverse, m) == NM_MATCH_SPEC_NO_MATCH);
}
g_slist_free (specs_reverse);
g_slist_free_full (specs, g_free);
}
static void
test_nm_match_spec_interface_name (void)
{
#define S(...) ((const char *[]) { __VA_ARGS__, NULL } )
test_match_spec_ifname ("em1",
S ("em1"),
NULL);
test_match_spec_ifname ("em1,em2",
S ("em1", "em2"),
NULL);
test_match_spec_ifname ("em1,em2,interface-name:em2",
S ("em1", "em2"),
NULL);
test_match_spec_ifname ("interface-name:em1",
S ("em1"),
NULL);
test_match_spec_ifname ("interface-name:em*",
S ("em", "em*", "em\\", "em\\*", "em\\1", "em\\11", "em\\2", "em1", "em11", "em2", "em3"),
NULL);
test_match_spec_ifname ("interface-name:em\\*",
S ("em\\", "em\\*", "em\\1", "em\\11", "em\\2"),
NULL);
test_match_spec_ifname ("interface-name:~em\\*",
S ("em\\", "em\\*", "em\\1", "em\\11", "em\\2"),
NULL);
test_match_spec_ifname ("interface-name:=em*",
S ("em*"),
NULL);
test_match_spec_ifname ("interface-name:em*,except:interface-name:em1*",
S ("em", "em*", "em\\", "em\\*", "em\\1", "em\\11", "em\\2", "em2", "em3"),
S ("em1", "em11"));
test_match_spec_ifname ("interface-name:em*,except:interface-name:=em*",
S ("em", "em\\", "em\\*", "em\\1", "em\\11", "em\\2", "em1", "em11", "em2", "em3"),
S ("em*"));
test_match_spec_ifname ("aa,bb,cc\\,dd,e,,",
S ("aa", "bb", "cc,dd", "e"),
NULL);
test_match_spec_ifname ("aa;bb;cc\\;dd;e,;",
S ("aa", "bb", "cc;dd", "e"),
NULL);
test_match_spec_ifname ("interface-name:em\\;1,em\\,2,\\,,\\\\,,em\\\\x",
S ("em;1", "em,2", ",", "\\", "em\\x"),
NULL);
test_match_spec_ifname (" , interface-name:a, ,",
S (" ", " ", " interface-name:a"),
NULL);
#undef S
}
/*******************************************/
NMTST_DEFINE (); NMTST_DEFINE ();
int int
@@ -797,6 +909,7 @@ main (int argc, char **argv)
g_test_add_func ("/general/connection-sort/autoconnect-priority", test_connection_sort_autoconnect_priority); g_test_add_func ("/general/connection-sort/autoconnect-priority", test_connection_sort_autoconnect_priority);
g_test_add_func ("/general/nm_utils_uuid_generate_from_strings", test_nm_utils_uuid_generate_from_strings); g_test_add_func ("/general/nm_utils_uuid_generate_from_strings", test_nm_utils_uuid_generate_from_strings);
g_test_add_func ("/general/nm_match_spec_interface_name", test_nm_match_spec_interface_name);
return g_test_run (); return g_test_run ();
} }