summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2019-04-11 21:20:11 +0200
committerThomas Haller <thaller@redhat.com>2019-04-16 12:57:55 +0200
commitdf8ef711771f15bfafcc98fc81e49e1a79342a2c (patch)
treeef2495bf293424a19663fe880424e20b403ab3bf
parent354ebb1356aabbaf5873fd61bc2eb561b1f89e2d (diff)
downloadNetworkManager-df8ef711771f15bfafcc98fc81e49e1a79342a2c.tar.gz
shared: add nm_utils_escaped_tokens_escape()
This escapes strings so that they can be concatenated with a delimiter and without loss tokenized with nm_utils_escaped_tokens_split(). Note that this is similar to _nm_utils_escape_plain() and _nm_utils_escape_spaces(). The difference is that nm_utils_escaped_tokens_escape() also escapes the last trailing whitespace. That means, if delimiters contains all NM_ASCII_SPACES, then it is identical to _nm_utils_escape_spaces(). Otherwise, the trailing space is treated specially. That is, because nm_utils_escaped_tokens_split() uses NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP, to strip leading and trailing whitespace. To still express a trailing whitespace, the last whitespace must be escaped. Note that NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP also honors escaping any whitespace (not only at the last position), but when escaping we don't need to escape them, because unescaped (non-trailing) whitespace are taken just fine. The pair nm_utils_escaped_tokens_split() and nm_utils_escaped_tokens_escape() are proposed as default way of tokenizing a list of items. For example, with $ nmcli connection modify "$PROFILE" +ipv4.routing-rules 'priority 5 from 192.168.7.5/32 table 5, priority 6 iif a\, from 192.168.7.5/32 table 6' Here we implement a to/from string function to handle one item (nm_ip_routing_rule_{from,to}_string()). When such elements are combined with ',', then we need to support an additional layer of escaping on top of that. The advantage is that the indvidual to/from string functions are agnostic to this second layer of escaping/tokenizing that nmcli employs to handle a list of these items. The disadvantage is that we possibly get multiple layers of backslash escapings. That is only mitigated by the fact that nm_utils_escaped_tokens_*() supports a syntax for which *most* characters don't need any special escaping. Only delimiters, backslash, and the trailing space needs escaping, and these are cases are expected to be few.
-rw-r--r--shared/nm-utils/nm-shared-utils.c76
-rw-r--r--shared/nm-utils/nm-shared-utils.h31
2 files changed, 107 insertions, 0 deletions
diff --git a/shared/nm-utils/nm-shared-utils.c b/shared/nm-utils/nm-shared-utils.c
index 1a86778e81..51d33b4911 100644
--- a/shared/nm-utils/nm-shared-utils.c
+++ b/shared/nm-utils/nm-shared-utils.c
@@ -1216,6 +1216,82 @@ done2:
return ptr;
}
+/*****************************************************************************/
+
+const char *
+nm_utils_escaped_tokens_escape (const char *str,
+ const char *delimiters,
+ char **out_to_free)
+{
+ guint8 ch_lookup[256];
+ char *ret;
+ gsize str_len;
+ gsize alloc_len;
+ gsize n_escapes;
+ gsize i, j;
+ gboolean escape_trailing_space;
+
+ if (!delimiters) {
+ nm_assert (delimiters);
+ delimiters = NM_ASCII_SPACES;
+ }
+
+ if (!str || str[0] == '\0') {
+ *out_to_free = NULL;
+ return str;
+ }
+
+ _char_lookup_table_init (ch_lookup, delimiters);
+
+ /* also mark '\\' as requiring escaping. */
+ ch_lookup[((guint8) '\\')] = 1;
+
+ n_escapes = 0;
+ for (i = 0; str[i] != '\0'; i++) {
+ if (_char_lookup_has (ch_lookup, str[i]))
+ n_escapes++;
+ }
+
+ str_len = i;
+ nm_assert (str_len > 0 && strlen (str) == str_len);
+
+ escape_trailing_space = !_char_lookup_has (ch_lookup, str[str_len - 1])
+ && g_ascii_isspace (str[str_len - 1]);
+
+ if ( n_escapes == 0
+ && !escape_trailing_space) {
+ *out_to_free = NULL;
+ return str;
+ }
+
+ alloc_len = str_len + n_escapes + ((gsize) escape_trailing_space) + 1;
+ ret = g_new (char, alloc_len);
+
+ j = 0;
+ for (i = 0; str[i] != '\0'; i++) {
+ if (_char_lookup_has (ch_lookup, str[i])) {
+ nm_assert (j < alloc_len);
+ ret[j++] = '\\';
+ }
+ nm_assert (j < alloc_len);
+ ret[j++] = str[i];
+ }
+ if (escape_trailing_space) {
+ nm_assert (!_char_lookup_has (ch_lookup, ret[j - 1]) && g_ascii_isspace (ret[j - 1]));
+ ret[j] = ret[j - 1];
+ ret[j - 1] = '\\';
+ j++;
+ }
+
+ nm_assert (j == alloc_len - 1);
+ ret[j] = '\0';
+
+ *out_to_free = ret;
+ return ret;
+}
+
+/*****************************************************************************/
+
/**
* nm_utils_strv_find_first:
* @list: the strv list to search
diff --git a/shared/nm-utils/nm-shared-utils.h b/shared/nm-utils/nm-shared-utils.h
index 25e77b9b8b..aeb1e2a1c6 100644
--- a/shared/nm-utils/nm-shared-utils.h
+++ b/shared/nm-utils/nm-shared-utils.h
@@ -409,6 +409,37 @@ char **_nm_utils_strv_cleanup (char **strv,
/*****************************************************************************/
+static inline const char **
+nm_utils_escaped_tokens_split (const char *str,
+ const char *delimiters)
+{
+ return nm_utils_strsplit_set_full (str,
+ delimiters,
+ NM_UTILS_STRSPLIT_SET_FLAGS_ESCAPED
+ | NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP);
+}
+
+const char *nm_utils_escaped_tokens_escape (const char *str,
+ const char *delimiters,
+ char **out_to_free);
+
+static inline GString *
+nm_utils_escaped_tokens_escape_gstr (const char *str,
+ const char *delimiters,
+ GString *gstring)
+{
+ gs_free char *str_to_free = NULL;
+
+ nm_assert (str);
+ nm_assert (gstring);
+
+ g_string_append (gstring,
+ nm_utils_escaped_tokens_escape (str, delimiters, &str_to_free));
+ return gstring;
+}
+
+/*****************************************************************************/
+
#define NM_UTILS_CHECKSUM_LENGTH_MD5 16
#define NM_UTILS_CHECKSUM_LENGTH_SHA1 20
#define NM_UTILS_CHECKSUM_LENGTH_SHA256 32