summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2019-04-11 19:24:15 +0200
committerThomas Haller <thaller@redhat.com>2019-04-17 11:11:21 +0200
commit9522aaf22678e57787e3def3baf956bb5457fe20 (patch)
treee07be4282af44745ad4378cfc22cd86306c92220
parent5b2b0dcadfd40883865f5ce4e3f8632008b2d973 (diff)
downloadNetworkManager-9522aaf22678e57787e3def3baf956bb5457fe20.tar.gz
shared: add NM_UTILS_STRSPLIT_SET_FLAGS_ESCAPED to nm_utils_strsplit_set_full()
Add a new flag that will remove escape characters after splitting the string. This implements a special kind of backslash escaping. It's not C escape sequences (like '\n' or '\020'), but simply to take the special character following the backslash verbatim. Note that the backslash is only considered special, if it's followed by a delimiter, another backslash, or a whitespace (in combination with %NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP). The main purpose of this form of escaping is nmcli's list options, like $ 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' It's a contrieved example, but the list options are a list of IP addresses, rules, etc. They implement their own syntax for one element, and are concatenated by ','. To support that one element may have arbitrary characters (including the delimiter and whitespaces), nmcli employs a tokenization with this special kind of escaping.
-rw-r--r--shared/nm-utils/nm-shared-utils.c27
-rw-r--r--shared/nm-utils/nm-shared-utils.h27
2 files changed, 53 insertions, 1 deletions
diff --git a/shared/nm-utils/nm-shared-utils.c b/shared/nm-utils/nm-shared-utils.c
index c21f0f66ec..1a86778e81 100644
--- a/shared/nm-utils/nm-shared-utils.c
+++ b/shared/nm-utils/nm-shared-utils.c
@@ -1027,7 +1027,8 @@ nm_utils_strsplit_set_full (const char *str,
const char *c_str;
char *s;
guint8 ch_lookup[256];
- const gboolean f_allow_escaping = NM_FLAGS_HAS (flags, NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING);
+ const gboolean f_escaped = NM_FLAGS_HAS (flags, NM_UTILS_STRSPLIT_SET_FLAGS_ESCAPED);
+ const gboolean f_allow_escaping = f_escaped || NM_FLAGS_HAS (flags, NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING);
const gboolean f_preserve_empty = NM_FLAGS_HAS (flags, NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY);
const gboolean f_strstrip = NM_FLAGS_HAS (flags, NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP);
@@ -1188,6 +1189,30 @@ done2:
ptr[i_token] = NULL;
}
+ if (f_escaped) {
+ gsize i, j;
+
+ /* We no longer need ch_lookup for its original purpose. Modify it, so it
+ * can detect the delimiters, '\\', and (optionally) whitespaces. */
+ ch_lookup[((guint8) '\\')] = 1;
+ if (f_strstrip) {
+ for (i = 0; NM_ASCII_SPACES[i]; i++)
+ ch_lookup[((guint8) (NM_ASCII_SPACES[i]))] = 1;
+ }
+
+ for (i_token = 0; ptr[i_token]; i_token++) {
+ s = (char *) ptr[i_token];
+ j = 0;
+ for (i = 0; s[i] != '\0'; ) {
+ if ( s[i] == '\\'
+ && _char_lookup_has (ch_lookup, s[i + 1]))
+ i++;
+ s[j++] = s[i++];
+ }
+ s[j] = '\0';
+ }
+ }
+
return ptr;
}
diff --git a/shared/nm-utils/nm-shared-utils.h b/shared/nm-utils/nm-shared-utils.h
index 0beb75ff10..25e77b9b8b 100644
--- a/shared/nm-utils/nm-shared-utils.h
+++ b/shared/nm-utils/nm-shared-utils.h
@@ -347,6 +347,33 @@ typedef enum {
* - when combined with %NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING,
* trailing whitespace escaped by backslash are not stripped. */
NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP = (1u << 2),
+
+ /* This implies %NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING.
+ *
+ * This will do a final run over all tokens and remove all backslash
+ * escape characters that
+ * - precede a delimiter.
+ * - precede a backslash.
+ * - preceed a whitespace (with %NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP).
+ *
+ * Note that with %NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP, it is only
+ * necessary to escape the very last whitespace (if the delimiters
+ * are not whitespace themself). So, technically, it would be sufficient
+ * to only unescape a backslash before the last whitespace and the user
+ * still could express everything. However, such a rule would be complicated
+ * to understand, so when using backslash escaping with nm_utils_strsplit_set_full(),
+ * then all characters (including backslash) are treated verbatim, except:
+ *
+ * - "\\$DELIMITER" (escaped delimiter)
+ * - "\\\\" (escaped backslash)
+ * - "\\$SPACE" (escaped space) (with %NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP).
+ *
+ * Note that all other escapes like "\\n" or "\\001" are left alone.
+ * That makes the escaping/unescaping rules simple. Also, for the most part
+ * a text is just taken as-is, with little additional rules. Only backslashes
+ * need extra care, and then only if they proceed one of the relevant characters.
+ */
+ NM_UTILS_STRSPLIT_SET_FLAGS_ESCAPED = (1u << 3),
} NMUtilsStrsplitSetFlags;
const char **nm_utils_strsplit_set_full (const char *str,