Commit 71dca95d authored by Andy Shevchenko's avatar Andy Shevchenko Committed by Linus Torvalds

lib/vsprintf: add %*pE[achnops] format specifier

This allows user to print a given buffer as an escaped string.  The
rules are applied according to an optional mix of flags provided by
additional format letters.

For example, if the given buffer is:

    1b 62 20 5c 43 07 22 90 0d 5d

The result strings would be:
    %*pE            "\eb \C\a"\220\r]"
    %*pEhp          "\x1bb \C\x07"\x90\x0d]"
    %*pEa           "\e\142\040\\\103\a\042\220\r\135"

Please, read Documentation/printk-formats.txt and lib/string_helpers.c
kernel documentation to get further information.

[akpm@linux-foundation.org: tidy up comment layout, per Joe]
Signed-off-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Suggested-by: default avatarJoe Perches <joe@perches.com>
Cc: "John W . Linville" <linville@tuxdriver.com>
Cc: Johannes Berg <johannes@sipsolutions.net>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent c8250381
...@@ -70,6 +70,38 @@ DMA addresses types dma_addr_t: ...@@ -70,6 +70,38 @@ DMA addresses types dma_addr_t:
For printing a dma_addr_t type which can vary based on build options, For printing a dma_addr_t type which can vary based on build options,
regardless of the width of the CPU data path. Passed by reference. regardless of the width of the CPU data path. Passed by reference.
Raw buffer as an escaped string:
%*pE[achnops]
For printing raw buffer as an escaped string. For the following buffer
1b 62 20 5c 43 07 22 90 0d 5d
few examples show how the conversion would be done (the result string
without surrounding quotes):
%*pE "\eb \C\a"\220\r]"
%*pEhp "\x1bb \C\x07"\x90\x0d]"
%*pEa "\e\142\040\\\103\a\042\220\r\135"
The conversion rules are applied according to an optional combination
of flags (see string_escape_mem() kernel documentation for the
details):
a - ESCAPE_ANY
c - ESCAPE_SPECIAL
h - ESCAPE_HEX
n - ESCAPE_NULL
o - ESCAPE_OCTAL
p - ESCAPE_NP
s - ESCAPE_SPACE
By default ESCAPE_ANY_NP is used.
ESCAPE_ANY_NP is the sane choice for many cases, in particularly for
printing SSIDs.
If field width is omitted the 1 byte only will be escaped.
Raw buffer as a hex string: Raw buffer as a hex string:
%*ph 00 01 02 ... 3f %*ph 00 01 02 ... 3f
%*phC 00:01:02: ... :3f %*phC 00:01:02: ... :3f
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <asm/page.h> /* for PAGE_SIZE */ #include <asm/page.h> /* for PAGE_SIZE */
#include <asm/sections.h> /* for dereference_function_descriptor() */ #include <asm/sections.h> /* for dereference_function_descriptor() */
#include <linux/string_helpers.h>
#include "kstrtox.h" #include "kstrtox.h"
/** /**
...@@ -1100,6 +1101,62 @@ char *ip4_addr_string_sa(char *buf, char *end, const struct sockaddr_in *sa, ...@@ -1100,6 +1101,62 @@ char *ip4_addr_string_sa(char *buf, char *end, const struct sockaddr_in *sa,
return string(buf, end, ip4_addr, spec); return string(buf, end, ip4_addr, spec);
} }
static noinline_for_stack
char *escaped_string(char *buf, char *end, u8 *addr, struct printf_spec spec,
const char *fmt)
{
bool found = true;
int count = 1;
unsigned int flags = 0;
int len;
if (spec.field_width == 0)
return buf; /* nothing to print */
if (ZERO_OR_NULL_PTR(addr))
return string(buf, end, NULL, spec); /* NULL pointer */
do {
switch (fmt[count++]) {
case 'a':
flags |= ESCAPE_ANY;
break;
case 'c':
flags |= ESCAPE_SPECIAL;
break;
case 'h':
flags |= ESCAPE_HEX;
break;
case 'n':
flags |= ESCAPE_NULL;
break;
case 'o':
flags |= ESCAPE_OCTAL;
break;
case 'p':
flags |= ESCAPE_NP;
break;
case 's':
flags |= ESCAPE_SPACE;
break;
default:
found = false;
break;
}
} while (found);
if (!flags)
flags = ESCAPE_ANY_NP;
len = spec.field_width < 0 ? 1 : spec.field_width;
/* Ignore the error. We print as many characters as we can */
string_escape_mem(addr, len, &buf, end - buf, flags, NULL);
return buf;
}
static noinline_for_stack static noinline_for_stack
char *uuid_string(char *buf, char *end, const u8 *addr, char *uuid_string(char *buf, char *end, const u8 *addr,
struct printf_spec spec, const char *fmt) struct printf_spec spec, const char *fmt)
...@@ -1221,6 +1278,17 @@ int kptr_restrict __read_mostly; ...@@ -1221,6 +1278,17 @@ int kptr_restrict __read_mostly;
* - '[Ii][4S][hnbl]' IPv4 addresses in host, network, big or little endian order * - '[Ii][4S][hnbl]' IPv4 addresses in host, network, big or little endian order
* - 'I[6S]c' for IPv6 addresses printed as specified by * - 'I[6S]c' for IPv6 addresses printed as specified by
* http://tools.ietf.org/html/rfc5952 * http://tools.ietf.org/html/rfc5952
* - 'E[achnops]' For an escaped buffer, where rules are defined by combination
* of the following flags (see string_escape_mem() for the
* details):
* a - ESCAPE_ANY
* c - ESCAPE_SPECIAL
* h - ESCAPE_HEX
* n - ESCAPE_NULL
* o - ESCAPE_OCTAL
* p - ESCAPE_NP
* s - ESCAPE_SPACE
* By default ESCAPE_ANY_NP is used.
* - 'U' For a 16 byte UUID/GUID, it prints the UUID/GUID in the form * - 'U' For a 16 byte UUID/GUID, it prints the UUID/GUID in the form
* "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" * "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
* Options for %pU are: * Options for %pU are:
...@@ -1321,6 +1389,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, ...@@ -1321,6 +1389,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
}} }}
} }
break; break;
case 'E':
return escaped_string(buf, end, ptr, spec, fmt);
case 'U': case 'U':
return uuid_string(buf, end, ptr, spec, fmt); return uuid_string(buf, end, ptr, spec, fmt);
case 'V': case 'V':
...@@ -1633,6 +1703,7 @@ int format_decode(const char *fmt, struct printf_spec *spec) ...@@ -1633,6 +1703,7 @@ int format_decode(const char *fmt, struct printf_spec *spec)
* %piS depending on sa_family of 'struct sockaddr *' print IPv4/IPv6 address * %piS depending on sa_family of 'struct sockaddr *' print IPv4/IPv6 address
* %pU[bBlL] print a UUID/GUID in big or little endian using lower or upper * %pU[bBlL] print a UUID/GUID in big or little endian using lower or upper
* case. * case.
* %*pE[achnops] print an escaped buffer
* %*ph[CDN] a variable-length hex string with a separator (supports up to 64 * %*ph[CDN] a variable-length hex string with a separator (supports up to 64
* bytes of the input) * bytes of the input)
* %n is ignored * %n is ignored
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment