mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-07 09:00:21 +01:00
ifcfg-rh: support storing newline '\n' and other ANSI control caracters
This is especially important for the team config JSON, which is expected to contain newlines. ANSI C quotation is bash specific, but initscripts already use #!/bin/bash. Unfortunately, g_strescape() doesn't escape '\'' and can thus not be used. Also add a test that svEscape() and svUnescape() do a round-trip. Not only consider \r and \n as candidates for ANSI C quotation, but all ANSI control characters.
This commit is contained in:
parent
7b548fb9a8
commit
c55b7e866e
2 changed files with 101 additions and 10 deletions
|
|
@ -99,15 +99,88 @@ _shell_is_name (const char *key)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* like g_strescape(), except that it also escapes '\''' *sigh*.
|
||||
*
|
||||
* While at it, add $''. */
|
||||
static char *
|
||||
_escape_ansic (const char *source)
|
||||
{
|
||||
const char *p;
|
||||
gchar *dest;
|
||||
gchar *q;
|
||||
|
||||
nm_assert (source);
|
||||
|
||||
p = (const char *) source;
|
||||
/* Each source byte needs maximally four destination chars (\777) */
|
||||
q = dest = g_malloc (strlen (source) * 4 + 1 + 3);
|
||||
|
||||
*q++ = '$';
|
||||
*q++ = '\'';
|
||||
|
||||
while (*p) {
|
||||
switch (*p) {
|
||||
case '\b':
|
||||
*q++ = '\\';
|
||||
*q++ = 'b';
|
||||
break;
|
||||
case '\f':
|
||||
*q++ = '\\';
|
||||
*q++ = 'f';
|
||||
break;
|
||||
case '\n':
|
||||
*q++ = '\\';
|
||||
*q++ = 'n';
|
||||
break;
|
||||
case '\r':
|
||||
*q++ = '\\';
|
||||
*q++ = 'r';
|
||||
break;
|
||||
case '\t':
|
||||
*q++ = '\\';
|
||||
*q++ = 't';
|
||||
break;
|
||||
case '\v':
|
||||
*q++ = '\\';
|
||||
*q++ = 'v';
|
||||
break;
|
||||
case '\\':
|
||||
case '"':
|
||||
case '\'':
|
||||
*q++ = '\\';
|
||||
*q++ = *p;
|
||||
break;
|
||||
default:
|
||||
if ((*p < ' ') || (*p >= 0177)) {
|
||||
*q++ = '\\';
|
||||
*q++ = '0' + (((*p) >> 6) & 07);
|
||||
*q++ = '0' + (((*p) >> 3) & 07);
|
||||
*q++ = '0' + ((*p) & 07);
|
||||
} else
|
||||
*q++ = *p;
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
*q++ = '\'';
|
||||
*q++ = '\0';
|
||||
|
||||
nm_assert (q - dest <= strlen (source) * 4 + 1 + 3);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#define ESC_ESCAPEES "\"'\\$~`" /* must be escaped */
|
||||
#define ESC_SPACES " \t|&;()<>" /* only require "" */
|
||||
#define ESC_NEWLINES "\n\r" /* will be removed */
|
||||
|
||||
const char *
|
||||
svEscape (const char *s, char **to_free)
|
||||
{
|
||||
char *new;
|
||||
int mangle = 0, space = 0, newline = 0;
|
||||
gsize mangle = 0;
|
||||
gboolean has_space = FALSE;
|
||||
int newlen;
|
||||
size_t i, j, slen;
|
||||
|
||||
|
|
@ -117,23 +190,26 @@ svEscape (const char *s, char **to_free)
|
|||
if (strchr (ESC_ESCAPEES, s[i]))
|
||||
mangle++;
|
||||
if (strchr (ESC_SPACES, s[i]))
|
||||
space++;
|
||||
if (strchr (ESC_NEWLINES, s[i]))
|
||||
newline++;
|
||||
has_space = TRUE;
|
||||
if (s[i] < ' ') {
|
||||
/* if the string contains newline we can only express it using ANSI C quotation
|
||||
* (as we don't support line continuation).
|
||||
* Additionally, ANSI control characters look odd with regular quotation, so handle
|
||||
* them too. */
|
||||
return (*to_free = _escape_ansic (s));
|
||||
}
|
||||
}
|
||||
if (!mangle && !space && !newline) {
|
||||
if (!mangle && !has_space) {
|
||||
*to_free = NULL;
|
||||
return s;
|
||||
}
|
||||
|
||||
newlen = slen + mangle - newline + 3; /* 3 is extra ""\0 */
|
||||
newlen = slen + mangle + 3; /* 3 is extra ""\0 */
|
||||
new = g_malloc (newlen);
|
||||
|
||||
j = 0;
|
||||
new[j++] = '"';
|
||||
for (i = 0; i < slen; i++) {
|
||||
if (strchr (ESC_NEWLINES, s[i]))
|
||||
continue;
|
||||
if (strchr (ESC_ESCAPEES, s[i])) {
|
||||
new[j++] = '\\';
|
||||
}
|
||||
|
|
@ -142,7 +218,7 @@ svEscape (const char *s, char **to_free)
|
|||
new[j++] = '"';
|
||||
new[j++] = '\0';
|
||||
|
||||
nm_assert (j == slen + mangle - newline + 3);
|
||||
nm_assert (j == slen + mangle + 3);
|
||||
|
||||
*to_free = new;
|
||||
return new;
|
||||
|
|
|
|||
|
|
@ -8730,6 +8730,21 @@ do_svUnescape_assert (const char *str, const char *expected)
|
|||
|
||||
s = _svUnescape (str, &to_free);
|
||||
g_assert_cmpstr (s, ==, expected);
|
||||
|
||||
/* check we can make a round-trip */
|
||||
if (expected) {
|
||||
gs_free char *s1_free = NULL;
|
||||
gs_free char *s2_free = NULL;
|
||||
const char *s1, *s2;
|
||||
|
||||
s1 = svEscape (expected, &s1_free);
|
||||
g_assert (s1);
|
||||
|
||||
s2 = _svUnescape (s1, &s2_free);
|
||||
g_assert (s2);
|
||||
|
||||
g_assert_cmpstr (s2, ==, expected);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue