diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml index 819c051e20..2eba34dff2 100644 --- a/man/NetworkManager.conf.xml +++ b/man/NetworkManager.conf.xml @@ -1685,6 +1685,55 @@ interface-name:vboxnet*,except:interface-name:vboxnet2 + + + Connection List Format + + Connections can be specified using the following format: + + + + + * + Matches every connection. + + + uuid:UUID + Match the connection by UUID, for example + "uuid:83037490-1d17-4986-a397-01f1db3a7fc2" + + + id=ID + Match the connection by name. + + + origin:ORIGIN + Match the connection by origin, stored in the + org.freedesktop.NetworkManager.origin tag of the user setting. For example, use + "except:origin:nm-initrd-generator" to forbid activation of connections created by the + initrd generator. + + + except:SPEC + Negative match of a connection. A negative match has higher priority then the positive + matches above. + If there is a list consisting only of negative matches, the behavior is the same as if there is also + match-all. That means, if none of all the negative matches is satisfied, the overall result is still a + positive match. + + + SPEC[,;]SPEC + Multiple specs can be concatenated with commas or semicolons. The order does not matter as + matches are either inclusive or negative (except:), with negative matches having higher + priority. + Backslash is supported to escape the separators ';' and ',', and to express special characters such as + newline ('\n'), tabulator ('\t'), whitespace ('\s') and backslash ('\\'). Whitespace is not a separator but + will be trimmed between two specs (unless escaped as '\s'). + + + + + diff --git a/src/core/nm-core-utils.c b/src/core/nm-core-utils.c index ec4d724454..eda63c5b4c 100644 --- a/src/core/nm-core-utils.c +++ b/src/core/nm-core-utils.c @@ -1484,6 +1484,112 @@ nm_match_spec_device(const GSList *specs, return _match_result(has_except, has_not_except, has_match, has_match_except); } +typedef struct { + const char *uuid; + const char *id; + const char *origin; +} MatchConnectionData; + +static gboolean +match_connection_eval(const char *spec_str, const MatchConnectionData *match_data) +{ + if (spec_str[0] == '*' && spec_str[1] == '\0') + return TRUE; + + if (_MATCH_CHECK(spec_str, "id:")) + return nm_streq0(spec_str, match_data->id); + + if (_MATCH_CHECK(spec_str, "uuid:")) + return nm_streq0(spec_str, match_data->uuid); + + if (_MATCH_CHECK(spec_str, "origin:")) + return nm_streq0(spec_str, match_data->origin); + + return FALSE; +} + +static NMMatchSpecMatchType +match_spec_connection(const GSList *specs, const char *id, const char *uuid, const char *origin) +{ + const GSList * iter; + gboolean has_match = FALSE; + gboolean has_match_except = FALSE; + gboolean has_except = FALSE; + gboolean has_not_except = FALSE; + const char * spec_str; + const MatchConnectionData match_data = { + .id = nm_str_not_empty(id), + .uuid = nm_str_not_empty(uuid), + .origin = nm_str_not_empty(origin), + }; + + if (!specs) + return NM_MATCH_SPEC_NO_MATCH; + + for (iter = specs; iter; iter = iter->next) { + gboolean except; + + spec_str = iter->data; + + if (!spec_str || !*spec_str) + continue; + + spec_str = match_except(spec_str, &except); + + if (except) + has_except = TRUE; + else + has_not_except = TRUE; + + if ((except && has_match_except) || (!except && has_match)) { + /* evaluating the match does not give new information. Skip it. */ + continue; + } + + if (!match_connection_eval(spec_str, &match_data)) + continue; + + if (except) + has_match_except = TRUE; + else + has_match = TRUE; + } + + return _match_result(has_except, has_not_except, has_match, has_match_except); +} + +int +nm_utils_connection_match_spec_list(NMConnection *connection, + const GSList *specs, + int no_match_value) +{ + NMMatchSpecMatchType m; + NMSettingUser * s_user; + const char * origin = NULL; + + if (!specs) + return no_match_value; + + s_user = _nm_connection_get_setting(connection, NM_TYPE_SETTING_USER); + if (s_user) + origin = nm_setting_user_get_data(s_user, NM_USER_TAG_ORIGIN); + + m = match_spec_connection(specs, + nm_connection_get_id(connection), + nm_connection_get_uuid(connection), + origin); + switch (m) { + case NM_MATCH_SPEC_MATCH: + return TRUE; + case NM_MATCH_SPEC_NEG_MATCH: + return FALSE; + case NM_MATCH_SPEC_NO_MATCH: + return no_match_value; + } + nm_assert_not_reached(); + return no_match_value; +} + static gboolean match_config_eval(const char *str, const char *tag, guint cur_nm_version) { diff --git a/src/core/nm-core-utils.h b/src/core/nm-core-utils.h index 920330bc43..a2b94e6711 100644 --- a/src/core/nm-core-utils.h +++ b/src/core/nm-core-utils.h @@ -211,6 +211,10 @@ gboolean nm_utils_kernel_cmdline_match_check(const char *const *proc_cmdline, guint num_patterns, GError ** error); +int nm_utils_connection_match_spec_list(NMConnection *connection, + const GSList *specs, + int no_match_value); + /*****************************************************************************/ gboolean nm_utils_connection_has_default_route(NMConnection *connection,