summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Shevchenko <andriy.shevchenko@linux.intel.com>2014-10-13 15:55:18 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2014-10-14 02:18:26 +0200
commit71dca95d5cf5ece6c1bee8e625e23c16025952c7 (patch)
tree098b1a20867ef6d1b38f549f162c160610b3cbff
parentc8250381c8272a9828fdd353171727b154fbd296 (diff)
downloadlwn-71dca95d5cf5ece6c1bee8e625e23c16025952c7.tar.gz
lwn-71dca95d5cf5ece6c1bee8e625e23c16025952c7.zip
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: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Suggested-by: Joe 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: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--Documentation/printk-formats.txt32
-rw-r--r--lib/vsprintf.c71
2 files changed, 103 insertions, 0 deletions
diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
index b4498218c474..5a615c14f75d 100644
--- a/Documentation/printk-formats.txt
+++ b/Documentation/printk-formats.txt
@@ -70,6 +70,38 @@ DMA addresses types dma_addr_t:
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.
+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:
%*ph 00 01 02 ... 3f
%*phC 00:01:02: ... :3f
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index ba3cd0a35640..ec337f64f52d 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -33,6 +33,7 @@
#include <asm/page.h> /* for PAGE_SIZE */
#include <asm/sections.h> /* for dereference_function_descriptor() */
+#include <linux/string_helpers.h>
#include "kstrtox.h"
/**
@@ -1101,6 +1102,62 @@ char *ip4_addr_string_sa(char *buf, char *end, const struct sockaddr_in *sa,
}
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
char *uuid_string(char *buf, char *end, const u8 *addr,
struct printf_spec spec, const char *fmt)
{
@@ -1221,6 +1278,17 @@ int kptr_restrict __read_mostly;
* - '[Ii][4S][hnbl]' IPv4 addresses in host, network, big or little endian order
* - 'I[6S]c' for IPv6 addresses printed as specified by
* 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
* "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
* Options for %pU are:
@@ -1321,6 +1389,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
}}
}
break;
+ case 'E':
+ return escaped_string(buf, end, ptr, spec, fmt);
case 'U':
return uuid_string(buf, end, ptr, spec, fmt);
case 'V':
@@ -1633,6 +1703,7 @@ qualifier:
* %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
* case.
+ * %*pE[achnops] print an escaped buffer
* %*ph[CDN] a variable-length hex string with a separator (supports up to 64
* bytes of the input)
* %n is ignored