mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-09 18:10:21 +01:00
core: support "except:" spec to negate match
Extend nm_match_spec_*() to support an "except:" prefix to negate
the result of a match. "except:" only works when followed by
an exact match type, for example "except:interface-name:vboxnet0",
but not "except:vboxnet0".
A matching "except:" spec always wins, regardless of other positive
matchings.
(cherry picked from commit 5c2e1afd1b)
This commit is contained in:
parent
3de7acc37a
commit
aaca52b261
6 changed files with 120 additions and 53 deletions
|
|
@ -833,47 +833,72 @@ nm_utils_find_helper(const char *progname, const char *try_first, GError **error
|
|||
#define MAC_TAG "mac:"
|
||||
#define INTERFACE_NAME_TAG "interface-name:"
|
||||
#define SUBCHAN_TAG "s390-subchannels:"
|
||||
#define EXCEPT_TAG "except:"
|
||||
|
||||
gboolean
|
||||
static const char *
|
||||
_match_except (const char *spec_str, gboolean *out_except)
|
||||
{
|
||||
if (!g_ascii_strncasecmp (spec_str, EXCEPT_TAG, STRLEN (EXCEPT_TAG))) {
|
||||
spec_str += STRLEN (EXCEPT_TAG);
|
||||
*out_except = TRUE;
|
||||
} else
|
||||
*out_except = FALSE;
|
||||
return spec_str;
|
||||
}
|
||||
|
||||
NMMatchSpecMatchType
|
||||
nm_match_spec_hwaddr (const GSList *specs, const char *hwaddr)
|
||||
{
|
||||
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)) {
|
||||
const char *spec_str = iter->data;
|
||||
gboolean except;
|
||||
|
||||
if (!spec_str || !*spec_str)
|
||||
continue;
|
||||
|
||||
spec_str = _match_except (spec_str, &except);
|
||||
|
||||
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))
|
||||
return TRUE;
|
||||
if (nm_utils_hwaddr_matches (spec_str, -1, hwaddr, -1)) {
|
||||
if (except)
|
||||
return NM_MATCH_SPEC_NEG_MATCH;
|
||||
match = NM_MATCH_SPEC_MATCH;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
return match;
|
||||
}
|
||||
|
||||
gboolean
|
||||
NMMatchSpecMatchType
|
||||
nm_match_spec_interface_name (const GSList *specs, const char *interface_name)
|
||||
{
|
||||
const GSList *iter;
|
||||
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);
|
||||
|
||||
for (iter = specs; iter; iter = g_slist_next (iter)) {
|
||||
const char *spec_str = iter->data;
|
||||
gboolean use_pattern = FALSE;
|
||||
gboolean except;
|
||||
|
||||
if (!spec_str || !*spec_str)
|
||||
continue;
|
||||
|
||||
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;
|
||||
|
|
@ -887,14 +912,17 @@ nm_match_spec_interface_name (const GSList *specs, const char *interface_name)
|
|||
spec_str += 1;
|
||||
use_pattern=TRUE;
|
||||
}
|
||||
}
|
||||
} else if (except)
|
||||
continue;
|
||||
|
||||
if (!strcmp (spec_str, interface_name))
|
||||
return TRUE;
|
||||
if (use_pattern && g_pattern_match_simple (spec_str, interface_name))
|
||||
return TRUE;
|
||||
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 FALSE;
|
||||
return match;
|
||||
}
|
||||
|
||||
#define BUFSIZE 10
|
||||
|
|
@ -963,34 +991,40 @@ parse_subchannels (const char *subchannels, guint32 *a, guint32 *b, guint32 *c)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
NMMatchSpecMatchType
|
||||
nm_match_spec_s390_subchannels (const GSList *specs, const char *subchannels)
|
||||
{
|
||||
const GSList *iter;
|
||||
guint32 a = 0, b = 0, 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))
|
||||
return FALSE;
|
||||
return NM_MATCH_SPEC_NO_MATCH;
|
||||
|
||||
for (iter = specs; iter; iter = g_slist_next (iter)) {
|
||||
const char *spec_str = iter->data;
|
||||
gboolean except;
|
||||
|
||||
if (!spec_str || !*spec_str)
|
||||
continue;
|
||||
|
||||
spec_str = _match_except (spec_str, &except);
|
||||
|
||||
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)
|
||||
return TRUE;
|
||||
if (a == spec_a && b == spec_b && c == spec_c) {
|
||||
if (except)
|
||||
return NM_MATCH_SPEC_NEG_MATCH;
|
||||
match = NM_MATCH_SPEC_MATCH;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
return match;
|
||||
}
|
||||
|
||||
const char *
|
||||
|
|
|
|||
|
|
@ -94,9 +94,15 @@ const char *nm_utils_find_helper (const char *progname,
|
|||
const char *try_first,
|
||||
GError **error);
|
||||
|
||||
gboolean nm_match_spec_hwaddr (const GSList *specs, const char *hwaddr);
|
||||
gboolean nm_match_spec_s390_subchannels (const GSList *specs, const char *subchannels);
|
||||
gboolean nm_match_spec_interface_name (const GSList *specs, const char *interface_name);
|
||||
typedef enum {
|
||||
NM_MATCH_SPEC_NO_MATCH = 0,
|
||||
NM_MATCH_SPEC_MATCH = 1,
|
||||
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);
|
||||
|
||||
const char *nm_utils_get_shared_wifi_permission (NMConnection *connection);
|
||||
|
||||
|
|
|
|||
|
|
@ -1495,15 +1495,19 @@ new_default_connection (NMDevice *self)
|
|||
return connection;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
static NMMatchSpecMatchType
|
||||
spec_match_list (NMDevice *device, const GSList *specs)
|
||||
{
|
||||
NMMatchSpecMatchType matched = NM_MATCH_SPEC_NO_MATCH, m;
|
||||
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device);
|
||||
|
||||
if (priv->subchannels && nm_match_spec_s390_subchannels (specs, priv->subchannels))
|
||||
return TRUE;
|
||||
|
||||
return NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->spec_match_list (device, specs);
|
||||
if (priv->subchannels)
|
||||
matched = nm_match_spec_s390_subchannels (specs, priv->subchannels);
|
||||
if (matched != NM_MATCH_SPEC_NEG_MATCH) {
|
||||
m = NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->spec_match_list (device, specs);
|
||||
matched = MAX (matched, m);
|
||||
}
|
||||
return matched;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -8209,27 +8209,30 @@ nm_device_spec_match_list (NMDevice *self, const GSList *specs)
|
|||
if (!specs)
|
||||
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)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
gboolean matched = FALSE;
|
||||
NMMatchSpecMatchType matched = NM_MATCH_SPEC_NO_MATCH, m;
|
||||
const GSList *iter;
|
||||
|
||||
for (iter = specs; iter; iter = g_slist_next (iter)) {
|
||||
if (!strcmp ((const char *) iter->data, "*"))
|
||||
return TRUE;
|
||||
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);
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
return matched;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ typedef struct {
|
|||
/* Sync deactivating (in the DISCONNECTED phase) */
|
||||
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 */
|
||||
void (* update_connection) (NMDevice *device, NMConnection *connection);
|
||||
|
|
|
|||
|
|
@ -803,7 +803,7 @@ _test_match_spec_contains (const char **matches, const char *match)
|
|||
}
|
||||
|
||||
static void
|
||||
test_match_spec_ifname (const char *spec_str, const char **matches)
|
||||
test_match_spec_ifname (const char *spec_str, const char **matches, const char **neg_matches)
|
||||
{
|
||||
const char *m;
|
||||
char **spec_str_split;
|
||||
|
|
@ -819,14 +819,20 @@ test_match_spec_ifname (const char *spec_str, const char **matches)
|
|||
specs = g_slist_reverse (g_slist_copy (specs_reverse));
|
||||
|
||||
for (i = 0; matches && matches[i]; i++) {
|
||||
g_assert (nm_match_spec_interface_name (specs, matches[i]));
|
||||
g_assert (nm_match_spec_interface_name (specs_reverse, matches[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;
|
||||
g_assert (!nm_match_spec_interface_name (specs, m));
|
||||
g_assert (!nm_match_spec_interface_name (specs_reverse, m));
|
||||
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);
|
||||
|
|
@ -839,20 +845,34 @@ test_nm_match_spec_interface_name (void)
|
|||
{
|
||||
#define S(...) ((const char *[]) { __VA_ARGS__, NULL } )
|
||||
test_match_spec_ifname ("em1",
|
||||
S ("em1"));
|
||||
S ("em1"),
|
||||
NULL);
|
||||
test_match_spec_ifname ("em1,em2",
|
||||
S ("em1", "em2"));
|
||||
S ("em1", "em2"),
|
||||
NULL);
|
||||
test_match_spec_ifname ("em1,em2,interface-name:em2",
|
||||
S ("em1", "em2"));
|
||||
S ("em1", "em2"),
|
||||
NULL);
|
||||
test_match_spec_ifname ("interface-name:em1",
|
||||
S ("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"));
|
||||
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"));
|
||||
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"));
|
||||
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*"));
|
||||
#undef S
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue