ifcfg-rh: restore previous behavior for svUnescape() stripping backslash from double-quoting

Now we could parse simple shell variable assignment properly, but old versions
of svEscape() wrote invalid double-quoted strings.

Add a hack to restore the broken behavior for that case only.
This commit is contained in:
Thomas Haller 2016-11-07 17:53:22 +01:00
parent ecda08e1d1
commit c5ac66d392
2 changed files with 60 additions and 3 deletions

View file

@ -245,6 +245,28 @@ svEscape (const char *s, char **to_free)
return new;
}
static gboolean
_looks_like_old_svescaped (const char *value)
{
gsize k;
if (value[0] != '"')
return FALSE;
for (k = 1; ; k++) {
if (value[k] == '\0')
return FALSE;
if (value[k] == '"')
return (value[k + 1] == '\0');
if (value[k] == '\\') {
k++;
if (!_char_in_strset (value[k], "\"'\\$~`"))
return FALSE;
} else if (_char_in_strset (value[k], "'\\$~`"))
return FALSE;
}
}
static gboolean
_ch_octal_is (char ch)
{
@ -302,6 +324,7 @@ svUnescape (const char *value, char **to_free)
{
gsize i, j;
nm_auto_free_gstring GString *str = NULL;
int looks_like_old_svescaped = -1;
/* we handle bash syntax here (note that ifup has #!/bin/bash.
* Thus, see https://www.gnu.org/software/bash/manual/html_node/Quoting.html#Quoting */
@ -404,7 +427,26 @@ svUnescape (const char *value, char **to_free)
/* we don't support line continuation */
goto out_error;
}
if (!NM_IN_SET (value[i], '$', '`', '"', '\\'))
if (NM_IN_SET (value[i], '$', '`', '"', '\\')) {
/* Drop the backslash. */
} else if (NM_IN_SET (value[i], '\'', '~')) {
/* '\'' and '~' in double qoutes are not handled special by shell.
* However, old versions of svEscape() would wrongly use double-quoting
* with backslash escaping for these characters (expecting svUnescape()
* to remove the backslash).
*
* In order to preserve previous behavior, we continue to read such
* strings different then shell does. */
/* Actually, we can relax this. Old svEscape() escaped the entire value
* in a particular way with double quotes.
* If the value doesn't exactly look like something as created by svEscape(),
* don't do the compat hack and preserve the backslash. */
if (looks_like_old_svescaped < 0)
looks_like_old_svescaped = _looks_like_old_svescaped (value);
if (!looks_like_old_svescaped)
g_string_append_c (str, '\\');
} else
g_string_append_c (str, '\\');
}
g_string_append_c (str, value[i]);

View file

@ -8233,8 +8233,6 @@ test_svUnescape (void)
V1 ("\"\\\\\"", "\\"),
V1 ("\"\\a\"", "\\a"),
V1 ("\"\\b\"", "\\b"),
V1 ("\"\\'\"", "\\'"),
V1 ("\"\\~\"", "\\~"),
V1 ("\"\\\t\"", "\\\t"),
V0 ("ab\r", "ab"),
V0 ("a'b'\r ", "ab"),
@ -8262,6 +8260,23 @@ test_svUnescape (void)
V1 ("\"aa\\\"\"", "aa\""),
V1 ("\"aa\\\"b\"c", "aa\"bc"),
V1 ("\"aa\\\"\"b", "aa\"b"),
/* the following is not shell behavior, but kept for backward compatibility
* with old svEscape(). */
V0 ("\"\\'\"", "'"),
V0 ("\"\\~\"", "~"),
V0 ("\"b\\~b\"", "b~b"),
V0 ("\"\\~\\~\"", "~~"),
V0 ("\"\\~\\'\"", "~'"),
/* the following is shell-behavior, because it doesn't look like written
* by old svEscape(). */
V1 ("\"\\~~\"", "\\~~"),
V1 ("\"\\a\\'\"", "\\a\\'"),
V1 ("x\"\\~\"", "x\\~"),
V1 ("\"\\'\"''", "\\'"),
V0 ("\"b\\~b\" ", "b\\~b"),
V1 ("\"b\\~b\"x", "b\\~bx"),
};
const UnescapeTestData data_ansi[] = {
/* strings inside $''. They cannot be compared directly, but must