util.c: add support for additional escape characters in string_quote

Quotes are not always used to denote string limits; printfd uses angle
brackets for that, for example.  As result, mechanism for supplying
set of additional characters in order to avoid ambiguities regarding
the end of the quoted string is needed.

* defs.h (string_quote): Add escape_chars parameter.
(print_quoted_string_ex): New function prototype.
* util.c (string_quote): Add escape_chars parameter.
(print_quoted_string_ex): Rename from print_quoted_string, add
escape_chars parameter, pass it to string_quote call.
(print_quoted_string): Turn into a thin wrapper around
print_quoted_string_ex.
(printstr_ex): Pass NULL as escape_chars argument of string_quote call.
* socketutils.c (unix_parse_response): Pass NULL as escape_chars
argument of string_quote call.
* tests/print_quoted_string.c (print_octal): New function.
print_quoted_memory_ex): Use it.  Add escape_chars parameter.
(print_quoted_memory): Pass NULL as escape_chars argument
of print_quoted_memory_ex call.
* tests/tests.h (print_quoted_string_ex, print_quoted_memory_ex): Add
escape_chars parameter.
* tests/fsync-y.c: Pass NULL as escape_chars argument of
print_quoted_string_ex call.

Co-Authored-by: Dmitry V. Levin <ldv@altlinux.org>
This commit is contained in:
Eugene Syromyatnikov 2018-02-02 18:46:29 +01:00 committed by Dmitry V. Levin
parent e196eebea4
commit 0b732f7e9d
6 changed files with 68 additions and 41 deletions

5
defs.h
View File

@ -534,7 +534,10 @@ str_strip_prefix_len(const char *str, const char *prefix, size_t prefix_len)
#define QUOTE_FORCE_HEX 0x10
#define QUOTE_EMIT_COMMENT 0x20
extern int string_quote(const char *, char *, unsigned int, unsigned int);
extern int string_quote(const char *, char *, unsigned int, unsigned int,
const char *escape_chars);
extern int print_quoted_string_ex(const char *, unsigned int, unsigned int,
const char *escape_chars);
extern int print_quoted_string(const char *, unsigned int, unsigned int);
extern int print_quoted_cstring(const char *, unsigned int);

View File

@ -331,10 +331,10 @@ unix_parse_response(const void *data, const int data_len,
if (path[0] == '\0') {
outstr[1] = '@';
string_quote(path + 1, outstr + 2,
path_len - 1, QUOTE_0_TERMINATED);
path_len - 1, QUOTE_0_TERMINATED, NULL);
} else {
string_quote(path, outstr + 1,
path_len, QUOTE_0_TERMINATED);
path_len, QUOTE_0_TERMINATED, NULL);
}
path_str = outstr;
} else {

View File

@ -60,7 +60,7 @@ main(void)
int rc = fsync(fd);
printf("fsync(%ld<", fd);
print_quoted_string_ex(dir, false);
print_quoted_string_ex(dir, false, NULL);
printf("/%s>) = %s\n", checks[i].fdstr, sprintrc(rc));
close(fd);

View File

@ -10,9 +10,9 @@
*/
void
print_quoted_string_ex(const char *instr, bool quote)
print_quoted_string_ex(const char *instr, bool quote, const char *escape_chars)
{
print_quoted_memory_ex(instr, strlen(instr), quote);
print_quoted_memory_ex(instr, strlen(instr), quote, escape_chars);
}
void
@ -33,9 +33,32 @@ print_quoted_cstring(const char *instr, const size_t size)
}
}
static void
print_octal(unsigned char c, char next)
{
putchar('\\');
char c1 = '0' + (c & 0x7);
char c2 = '0' + ((c >> 3) & 0x7);
char c3 = '0' + (c >> 6);
if (next >= '0' && next <= '7') {
/* Print \octal */
putchar(c3);
putchar(c2);
} else {
/* Print \[[o]o]o */
if (c3 != '0')
putchar(c3);
if (c3 != '0' || c2 != '0')
putchar(c2);
}
putchar(c1);
}
void
print_quoted_memory_ex(const void *const instr, const size_t len,
bool quote)
bool quote, const char *escape_chars)
{
const unsigned char *str = (const unsigned char *) instr;
size_t i;
@ -68,30 +91,14 @@ print_quoted_memory_ex(const void *const instr, const size_t len,
printf("\\v");
break;
default:
if (c >= ' ' && c <= 0x7e)
if (c >= ' ' && c <= 0x7e &&
!(escape_chars && strchr(escape_chars, c))) {
putchar(c);
else {
putchar('\\');
char c1 = '0' + (c & 0x7);
char c2 = '0' + ((c >> 3) & 0x7);
char c3 = '0' + (c >> 6);
if (i < (len - 1) &&
str[i + 1] >= '0' &&
str[i + 1] <= '7') {
/* Print \octal */
putchar(c3);
putchar(c2);
} else {
/* Print \[[o]o]o */
if (c3 != '0')
putchar(c3);
if (c3 != '0' || c2 != '0')
putchar(c2);
}
putchar(c1);
} else {
print_octal(c,
i < (len - 1) ? str[i + 1] : 0);
}
break;
}
}
@ -103,7 +110,7 @@ print_quoted_memory_ex(const void *const instr, const size_t len,
void
print_quoted_memory(const void *const instr, const size_t len)
{
print_quoted_memory_ex(instr, len, true);
print_quoted_memory_ex(instr, len, true, NULL);
}
void

View File

@ -142,8 +142,8 @@ const char *hexquote_strndup(const char *, size_t);
/* Return inode number of socket descriptor. */
unsigned long inode_of_sockfd(int);
/* Print string in a quoted form. */
void print_quoted_string_ex(const char *, bool quote);
/* Print string in a quoted form with optional escape characters. */
void print_quoted_string_ex(const char *, bool quote, const char *escape_str);
/* Print string in a quoted form. */
void print_quoted_string(const char *);
@ -154,8 +154,9 @@ void print_quoted_string(const char *);
*/
void print_quoted_cstring(const char *str, size_t size);
/* Print memory in a quoted form. */
void print_quoted_memory_ex(const void *, size_t, bool quote);
/* Print memory in a quoted form with optional escape characters. */
void print_quoted_memory_ex(const void *, size_t, bool quote,
const char *escape_chars);
/* Print memory in a quoted form. */
void print_quoted_memory(const void *, size_t);

30
util.c
View File

@ -446,6 +446,9 @@ printfd(struct tcb *tcp, int fd)
* Quote string `instr' of length `size'
* Write up to (3 + `size' * 4) bytes to `outstr' buffer.
*
* `escape_chars' specifies characters (in addition to characters with
* codes 0..31, 127..255, single and double quotes) that should be escaped.
*
* If QUOTE_0_TERMINATED `style' flag is set,
* treat `instr' as a NUL-terminated string,
* checking up to (`size' + 1) bytes of `instr'.
@ -458,12 +461,13 @@ printfd(struct tcb *tcp, int fd)
*/
int
string_quote(const char *instr, char *outstr, const unsigned int size,
const unsigned int style)
const unsigned int style, const char *escape_chars)
{
const unsigned char *ustr = (const unsigned char *) instr;
char *s = outstr;
unsigned int i;
int usehex, c, eol;
bool escape;
if (style & QUOTE_0_TERMINATED)
eol = '\0';
@ -552,9 +556,14 @@ string_quote(const char *instr, char *outstr, const unsigned int size,
*s++ = 'v';
break;
default:
if (c >= ' ' && c <= 0x7e)
escape = (c < ' ') || (c > 0x7e);
if (!escape && escape_chars)
escape = !!strchr(escape_chars, c);
if (!escape) {
*s++ = c;
else {
} else {
/* Print \octal */
*s++ = '\\';
if (i + 1 < size
@ -623,8 +632,8 @@ string_quote(const char *instr, char *outstr, const unsigned int size,
* Note that if QUOTE_0_TERMINATED is not set, always returns 1.
*/
int
print_quoted_string(const char *str, unsigned int size,
const unsigned int style)
print_quoted_string_ex(const char *str, unsigned int size,
const unsigned int style, const char *escape_chars)
{
char *buf;
char *outstr;
@ -655,13 +664,20 @@ print_quoted_string(const char *str, unsigned int size,
}
}
rc = string_quote(str, outstr, size, style);
rc = string_quote(str, outstr, size, style, escape_chars);
tprints(outstr);
free(buf);
return rc;
}
inline int
print_quoted_string(const char *str, unsigned int size,
const unsigned int style)
{
return print_quoted_string_ex(str, size, style, NULL);
}
/*
* Quote a NUL-terminated string `str' of length up to `size' - 1
* and print the result.
@ -783,7 +799,7 @@ printstr_ex(struct tcb *const tcp, const kernel_ulong_t addr,
/* If string_quote didn't see NUL and (it was supposed to be ASCIZ str
* or we were requested to print more than -s NUM chars)...
*/
ellipsis = string_quote(str, outstr, size, style)
ellipsis = string_quote(str, outstr, size, style, NULL)
&& len
&& ((style & QUOTE_0_TERMINATED)
|| len > max_strlen);