diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-13 21:54:50 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-13 21:54:50 -0400 |
| commit | dfe2c6dcc8ca2cdc662d7c0473e9811b72ef3370 (patch) | |
| tree | 9ed639a08c16322cdf136d576f42df5b97cd1549 /lib | |
| parent | a45d572841a24db02a62cf05e1157c35fdd3705b (diff) | |
| parent | 64e455079e1bd7787cc47be30b7f601ce682a5f6 (diff) | |
Merge branch 'akpm' (patches from Andrew Morton)
Merge second patch-bomb from Andrew Morton:
- a few hotfixes
- drivers/dma updates
- MAINTAINERS updates
- Quite a lot of lib/ updates
- checkpatch updates
- binfmt updates
- autofs4
- drivers/rtc/
- various small tweaks to less used filesystems
- ipc/ updates
- kernel/watchdog.c changes
* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (135 commits)
mm: softdirty: enable write notifications on VMAs after VM_SOFTDIRTY cleared
kernel/param: consolidate __{start,stop}___param[] in <linux/moduleparam.h>
ia64: remove duplicate declarations of __per_cpu_start[] and __per_cpu_end[]
frv: remove unused declarations of __start___ex_table and __stop___ex_table
kvm: ensure hard lockup detection is disabled by default
kernel/watchdog.c: control hard lockup detection default
staging: rtl8192u: use %*pEn to escape buffer
staging: rtl8192e: use %*pEn to escape buffer
staging: wlan-ng: use %*pEhp to print SN
lib80211: remove unused print_ssid()
wireless: hostap: proc: print properly escaped SSID
wireless: ipw2x00: print SSID via %*pE
wireless: libertas: print esaped string via %*pE
lib/vsprintf: add %*pE[achnops] format specifier
lib / string_helpers: introduce string_escape_mem()
lib / string_helpers: refactoring the test suite
lib / string_helpers: move documentation to c-file
include/linux: remove strict_strto* definitions
arch/x86/mm/numa.c: fix boot failure when all nodes are hotpluggable
fs: check bh blocknr earlier when searching lru
...
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/Kconfig.debug | 2 | ||||
| -rw-r--r-- | lib/Makefile | 4 | ||||
| -rw-r--r-- | lib/dynamic_debug.c | 17 | ||||
| -rw-r--r-- | lib/prio_heap.c | 70 | ||||
| -rw-r--r-- | lib/string.c | 28 | ||||
| -rw-r--r-- | lib/string_helpers.c | 312 | ||||
| -rw-r--r-- | lib/test-string_helpers.c | 277 | ||||
| -rw-r--r-- | lib/textsearch.c | 4 | ||||
| -rw-r--r-- | lib/vsprintf.c | 71 |
9 files changed, 662 insertions, 123 deletions
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index e7ad58c5fbeb..4e35a5d767ed 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug | |||
| @@ -1648,7 +1648,7 @@ config DMA_API_DEBUG | |||
| 1648 | 1648 | ||
| 1649 | If unsure, say N. | 1649 | If unsure, say N. |
| 1650 | 1650 | ||
| 1651 | config TEST_MODULE | 1651 | config TEST_LKM |
| 1652 | tristate "Test module loading with 'hello world' module" | 1652 | tristate "Test module loading with 'hello world' module" |
| 1653 | default n | 1653 | default n |
| 1654 | depends on m | 1654 | depends on m |
diff --git a/lib/Makefile b/lib/Makefile index d6b4bc496408..7512dc978f18 100644 --- a/lib/Makefile +++ b/lib/Makefile | |||
| @@ -11,7 +11,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \ | |||
| 11 | rbtree.o radix-tree.o dump_stack.o timerqueue.o\ | 11 | rbtree.o radix-tree.o dump_stack.o timerqueue.o\ |
| 12 | idr.o int_sqrt.o extable.o \ | 12 | idr.o int_sqrt.o extable.o \ |
| 13 | sha1.o md5.o irq_regs.o reciprocal_div.o argv_split.o \ | 13 | sha1.o md5.o irq_regs.o reciprocal_div.o argv_split.o \ |
| 14 | proportions.o flex_proportions.o prio_heap.o ratelimit.o show_mem.o \ | 14 | proportions.o flex_proportions.o ratelimit.o show_mem.o \ |
| 15 | is_single_threaded.o plist.o decompress.o kobject_uevent.o \ | 15 | is_single_threaded.o plist.o decompress.o kobject_uevent.o \ |
| 16 | earlycpio.o | 16 | earlycpio.o |
| 17 | 17 | ||
| @@ -31,7 +31,7 @@ obj-y += string_helpers.o | |||
| 31 | obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o | 31 | obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o |
| 32 | obj-y += kstrtox.o | 32 | obj-y += kstrtox.o |
| 33 | obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o | 33 | obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o |
| 34 | obj-$(CONFIG_TEST_MODULE) += test_module.o | 34 | obj-$(CONFIG_TEST_LKM) += test_module.o |
| 35 | obj-$(CONFIG_TEST_USER_COPY) += test_user_copy.o | 35 | obj-$(CONFIG_TEST_USER_COPY) += test_user_copy.o |
| 36 | obj-$(CONFIG_TEST_BPF) += test_bpf.o | 36 | obj-$(CONFIG_TEST_BPF) += test_bpf.o |
| 37 | obj-$(CONFIG_TEST_FIRMWARE) += test_firmware.o | 37 | obj-$(CONFIG_TEST_FIRMWARE) += test_firmware.o |
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 31fe79e31ab8..dfba05521748 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c | |||
| @@ -819,22 +819,9 @@ static const struct seq_operations ddebug_proc_seqops = { | |||
| 819 | */ | 819 | */ |
| 820 | static int ddebug_proc_open(struct inode *inode, struct file *file) | 820 | static int ddebug_proc_open(struct inode *inode, struct file *file) |
| 821 | { | 821 | { |
| 822 | struct ddebug_iter *iter; | ||
| 823 | int err; | ||
| 824 | |||
| 825 | vpr_info("called\n"); | 822 | vpr_info("called\n"); |
| 826 | 823 | return seq_open_private(file, &ddebug_proc_seqops, | |
| 827 | iter = kzalloc(sizeof(*iter), GFP_KERNEL); | 824 | sizeof(struct ddebug_iter)); |
| 828 | if (iter == NULL) | ||
| 829 | return -ENOMEM; | ||
| 830 | |||
| 831 | err = seq_open(file, &ddebug_proc_seqops); | ||
| 832 | if (err) { | ||
| 833 | kfree(iter); | ||
| 834 | return err; | ||
| 835 | } | ||
| 836 | ((struct seq_file *)file->private_data)->private = iter; | ||
| 837 | return 0; | ||
| 838 | } | 825 | } |
| 839 | 826 | ||
| 840 | static const struct file_operations ddebug_proc_fops = { | 827 | static const struct file_operations ddebug_proc_fops = { |
diff --git a/lib/prio_heap.c b/lib/prio_heap.c deleted file mode 100644 index a7af6f85eca8..000000000000 --- a/lib/prio_heap.c +++ /dev/null | |||
| @@ -1,70 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Simple insertion-only static-sized priority heap containing | ||
| 3 | * pointers, based on CLR, chapter 7 | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/slab.h> | ||
| 7 | #include <linux/prio_heap.h> | ||
| 8 | |||
| 9 | int heap_init(struct ptr_heap *heap, size_t size, gfp_t gfp_mask, | ||
| 10 | int (*gt)(void *, void *)) | ||
| 11 | { | ||
| 12 | heap->ptrs = kmalloc(size, gfp_mask); | ||
| 13 | if (!heap->ptrs) | ||
| 14 | return -ENOMEM; | ||
| 15 | heap->size = 0; | ||
| 16 | heap->max = size / sizeof(void *); | ||
| 17 | heap->gt = gt; | ||
| 18 | return 0; | ||
| 19 | } | ||
| 20 | |||
| 21 | void heap_free(struct ptr_heap *heap) | ||
| 22 | { | ||
| 23 | kfree(heap->ptrs); | ||
| 24 | } | ||
| 25 | |||
| 26 | void *heap_insert(struct ptr_heap *heap, void *p) | ||
| 27 | { | ||
| 28 | void *res; | ||
| 29 | void **ptrs = heap->ptrs; | ||
| 30 | int pos; | ||
| 31 | |||
| 32 | if (heap->size < heap->max) { | ||
| 33 | /* Heap insertion */ | ||
| 34 | pos = heap->size++; | ||
| 35 | while (pos > 0 && heap->gt(p, ptrs[(pos-1)/2])) { | ||
| 36 | ptrs[pos] = ptrs[(pos-1)/2]; | ||
| 37 | pos = (pos-1)/2; | ||
| 38 | } | ||
| 39 | ptrs[pos] = p; | ||
| 40 | return NULL; | ||
| 41 | } | ||
| 42 | |||
| 43 | /* The heap is full, so something will have to be dropped */ | ||
| 44 | |||
| 45 | /* If the new pointer is greater than the current max, drop it */ | ||
| 46 | if (heap->gt(p, ptrs[0])) | ||
| 47 | return p; | ||
| 48 | |||
| 49 | /* Replace the current max and heapify */ | ||
| 50 | res = ptrs[0]; | ||
| 51 | ptrs[0] = p; | ||
| 52 | pos = 0; | ||
| 53 | |||
| 54 | while (1) { | ||
| 55 | int left = 2 * pos + 1; | ||
| 56 | int right = 2 * pos + 2; | ||
| 57 | int largest = pos; | ||
| 58 | if (left < heap->size && heap->gt(ptrs[left], p)) | ||
| 59 | largest = left; | ||
| 60 | if (right < heap->size && heap->gt(ptrs[right], ptrs[largest])) | ||
| 61 | largest = right; | ||
| 62 | if (largest == pos) | ||
| 63 | break; | ||
| 64 | /* Push p down the heap one level and bump one up */ | ||
| 65 | ptrs[pos] = ptrs[largest]; | ||
| 66 | ptrs[largest] = p; | ||
| 67 | pos = largest; | ||
| 68 | } | ||
| 69 | return res; | ||
| 70 | } | ||
diff --git a/lib/string.c b/lib/string.c index f3c6ff596414..2fc20aa06f84 100644 --- a/lib/string.c +++ b/lib/string.c | |||
| @@ -27,14 +27,14 @@ | |||
| 27 | #include <linux/bug.h> | 27 | #include <linux/bug.h> |
| 28 | #include <linux/errno.h> | 28 | #include <linux/errno.h> |
| 29 | 29 | ||
| 30 | #ifndef __HAVE_ARCH_STRNICMP | 30 | #ifndef __HAVE_ARCH_STRNCASECMP |
| 31 | /** | 31 | /** |
| 32 | * strnicmp - Case insensitive, length-limited string comparison | 32 | * strncasecmp - Case insensitive, length-limited string comparison |
| 33 | * @s1: One string | 33 | * @s1: One string |
| 34 | * @s2: The other string | 34 | * @s2: The other string |
| 35 | * @len: the maximum number of characters to compare | 35 | * @len: the maximum number of characters to compare |
| 36 | */ | 36 | */ |
| 37 | int strnicmp(const char *s1, const char *s2, size_t len) | 37 | int strncasecmp(const char *s1, const char *s2, size_t len) |
| 38 | { | 38 | { |
| 39 | /* Yes, Virginia, it had better be unsigned */ | 39 | /* Yes, Virginia, it had better be unsigned */ |
| 40 | unsigned char c1, c2; | 40 | unsigned char c1, c2; |
| @@ -56,6 +56,14 @@ int strnicmp(const char *s1, const char *s2, size_t len) | |||
| 56 | } while (--len); | 56 | } while (--len); |
| 57 | return (int)c1 - (int)c2; | 57 | return (int)c1 - (int)c2; |
| 58 | } | 58 | } |
| 59 | EXPORT_SYMBOL(strncasecmp); | ||
| 60 | #endif | ||
| 61 | #ifndef __HAVE_ARCH_STRNICMP | ||
| 62 | #undef strnicmp | ||
| 63 | int strnicmp(const char *s1, const char *s2, size_t len) | ||
| 64 | { | ||
| 65 | return strncasecmp(s1, s2, len); | ||
| 66 | } | ||
| 59 | EXPORT_SYMBOL(strnicmp); | 67 | EXPORT_SYMBOL(strnicmp); |
| 60 | #endif | 68 | #endif |
| 61 | 69 | ||
| @@ -73,20 +81,6 @@ int strcasecmp(const char *s1, const char *s2) | |||
| 73 | EXPORT_SYMBOL(strcasecmp); | 81 | EXPORT_SYMBOL(strcasecmp); |
| 74 | #endif | 82 | #endif |
| 75 | 83 | ||
| 76 | #ifndef __HAVE_ARCH_STRNCASECMP | ||
| 77 | int strncasecmp(const char *s1, const char *s2, size_t n) | ||
| 78 | { | ||
| 79 | int c1, c2; | ||
| 80 | |||
| 81 | do { | ||
| 82 | c1 = tolower(*s1++); | ||
| 83 | c2 = tolower(*s2++); | ||
| 84 | } while ((--n > 0) && c1 == c2 && c1 != 0); | ||
| 85 | return c1 - c2; | ||
| 86 | } | ||
| 87 | EXPORT_SYMBOL(strncasecmp); | ||
| 88 | #endif | ||
| 89 | |||
| 90 | #ifndef __HAVE_ARCH_STRCPY | 84 | #ifndef __HAVE_ARCH_STRCPY |
| 91 | /** | 85 | /** |
| 92 | * strcpy - Copy a %NUL terminated string | 86 | * strcpy - Copy a %NUL terminated string |
diff --git a/lib/string_helpers.c b/lib/string_helpers.c index 29033f319aea..58b78ba57439 100644 --- a/lib/string_helpers.c +++ b/lib/string_helpers.c | |||
| @@ -8,6 +8,8 @@ | |||
| 8 | #include <linux/math64.h> | 8 | #include <linux/math64.h> |
| 9 | #include <linux/export.h> | 9 | #include <linux/export.h> |
| 10 | #include <linux/ctype.h> | 10 | #include <linux/ctype.h> |
| 11 | #include <linux/errno.h> | ||
| 12 | #include <linux/string.h> | ||
| 11 | #include <linux/string_helpers.h> | 13 | #include <linux/string_helpers.h> |
| 12 | 14 | ||
| 13 | /** | 15 | /** |
| @@ -168,6 +170,44 @@ static bool unescape_special(char **src, char **dst) | |||
| 168 | return true; | 170 | return true; |
| 169 | } | 171 | } |
| 170 | 172 | ||
| 173 | /** | ||
| 174 | * string_unescape - unquote characters in the given string | ||
| 175 | * @src: source buffer (escaped) | ||
| 176 | * @dst: destination buffer (unescaped) | ||
| 177 | * @size: size of the destination buffer (0 to unlimit) | ||
| 178 | * @flags: combination of the flags (bitwise OR): | ||
| 179 | * %UNESCAPE_SPACE: | ||
| 180 | * '\f' - form feed | ||
| 181 | * '\n' - new line | ||
| 182 | * '\r' - carriage return | ||
| 183 | * '\t' - horizontal tab | ||
| 184 | * '\v' - vertical tab | ||
| 185 | * %UNESCAPE_OCTAL: | ||
| 186 | * '\NNN' - byte with octal value NNN (1 to 3 digits) | ||
| 187 | * %UNESCAPE_HEX: | ||
| 188 | * '\xHH' - byte with hexadecimal value HH (1 to 2 digits) | ||
| 189 | * %UNESCAPE_SPECIAL: | ||
| 190 | * '\"' - double quote | ||
| 191 | * '\\' - backslash | ||
| 192 | * '\a' - alert (BEL) | ||
| 193 | * '\e' - escape | ||
| 194 | * %UNESCAPE_ANY: | ||
| 195 | * all previous together | ||
| 196 | * | ||
| 197 | * Description: | ||
| 198 | * The function unquotes characters in the given string. | ||
| 199 | * | ||
| 200 | * Because the size of the output will be the same as or less than the size of | ||
| 201 | * the input, the transformation may be performed in place. | ||
| 202 | * | ||
| 203 | * Caller must provide valid source and destination pointers. Be aware that | ||
| 204 | * destination buffer will always be NULL-terminated. Source string must be | ||
| 205 | * NULL-terminated as well. | ||
| 206 | * | ||
| 207 | * Return: | ||
| 208 | * The amount of the characters processed to the destination buffer excluding | ||
| 209 | * trailing '\0' is returned. | ||
| 210 | */ | ||
| 171 | int string_unescape(char *src, char *dst, size_t size, unsigned int flags) | 211 | int string_unescape(char *src, char *dst, size_t size, unsigned int flags) |
| 172 | { | 212 | { |
| 173 | char *out = dst; | 213 | char *out = dst; |
| @@ -202,3 +242,275 @@ int string_unescape(char *src, char *dst, size_t size, unsigned int flags) | |||
| 202 | return out - dst; | 242 | return out - dst; |
| 203 | } | 243 | } |
| 204 | EXPORT_SYMBOL(string_unescape); | 244 | EXPORT_SYMBOL(string_unescape); |
| 245 | |||
| 246 | static int escape_passthrough(unsigned char c, char **dst, size_t *osz) | ||
| 247 | { | ||
| 248 | char *out = *dst; | ||
| 249 | |||
| 250 | if (*osz < 1) | ||
| 251 | return -ENOMEM; | ||
| 252 | |||
| 253 | *out++ = c; | ||
| 254 | |||
| 255 | *dst = out; | ||
| 256 | *osz -= 1; | ||
| 257 | |||
| 258 | return 1; | ||
| 259 | } | ||
| 260 | |||
| 261 | static int escape_space(unsigned char c, char **dst, size_t *osz) | ||
| 262 | { | ||
| 263 | char *out = *dst; | ||
| 264 | unsigned char to; | ||
| 265 | |||
| 266 | if (*osz < 2) | ||
| 267 | return -ENOMEM; | ||
| 268 | |||
| 269 | switch (c) { | ||
| 270 | case '\n': | ||
| 271 | to = 'n'; | ||
| 272 | break; | ||
| 273 | case '\r': | ||
| 274 | to = 'r'; | ||
| 275 | break; | ||
| 276 | case '\t': | ||
| 277 | to = 't'; | ||
| 278 | break; | ||
| 279 | case '\v': | ||
| 280 | to = 'v'; | ||
| 281 | break; | ||
| 282 | case '\f': | ||
| 283 | to = 'f'; | ||
| 284 | break; | ||
| 285 | default: | ||
| 286 | return 0; | ||
| 287 | } | ||
| 288 | |||
| 289 | *out++ = '\\'; | ||
| 290 | *out++ = to; | ||
| 291 | |||
| 292 | *dst = out; | ||
| 293 | *osz -= 2; | ||
| 294 | |||
| 295 | return 1; | ||
| 296 | } | ||
| 297 | |||
| 298 | static int escape_special(unsigned char c, char **dst, size_t *osz) | ||
| 299 | { | ||
| 300 | char *out = *dst; | ||
| 301 | unsigned char to; | ||
| 302 | |||
| 303 | if (*osz < 2) | ||
| 304 | return -ENOMEM; | ||
| 305 | |||
| 306 | switch (c) { | ||
| 307 | case '\\': | ||
| 308 | to = '\\'; | ||
| 309 | break; | ||
| 310 | case '\a': | ||
| 311 | to = 'a'; | ||
| 312 | break; | ||
| 313 | case '\e': | ||
| 314 | to = 'e'; | ||
| 315 | break; | ||
| 316 | default: | ||
| 317 | return 0; | ||
| 318 | } | ||
| 319 | |||
| 320 | *out++ = '\\'; | ||
| 321 | *out++ = to; | ||
| 322 | |||
| 323 | *dst = out; | ||
| 324 | *osz -= 2; | ||
| 325 | |||
| 326 | return 1; | ||
| 327 | } | ||
| 328 | |||
| 329 | static int escape_null(unsigned char c, char **dst, size_t *osz) | ||
| 330 | { | ||
| 331 | char *out = *dst; | ||
| 332 | |||
| 333 | if (*osz < 2) | ||
| 334 | return -ENOMEM; | ||
| 335 | |||
| 336 | if (c) | ||
| 337 | return 0; | ||
| 338 | |||
| 339 | *out++ = '\\'; | ||
| 340 | *out++ = '0'; | ||
| 341 | |||
| 342 | *dst = out; | ||
| 343 | *osz -= 2; | ||
| 344 | |||
| 345 | return 1; | ||
| 346 | } | ||
| 347 | |||
| 348 | static int escape_octal(unsigned char c, char **dst, size_t *osz) | ||
| 349 | { | ||
| 350 | char *out = *dst; | ||
| 351 | |||
| 352 | if (*osz < 4) | ||
| 353 | return -ENOMEM; | ||
| 354 | |||
| 355 | *out++ = '\\'; | ||
| 356 | *out++ = ((c >> 6) & 0x07) + '0'; | ||
| 357 | *out++ = ((c >> 3) & 0x07) + '0'; | ||
| 358 | *out++ = ((c >> 0) & 0x07) + '0'; | ||
| 359 | |||
| 360 | *dst = out; | ||
| 361 | *osz -= 4; | ||
| 362 | |||
| 363 | return 1; | ||
| 364 | } | ||
| 365 | |||
| 366 | static int escape_hex(unsigned char c, char **dst, size_t *osz) | ||
| 367 | { | ||
| 368 | char *out = *dst; | ||
| 369 | |||
| 370 | if (*osz < 4) | ||
| 371 | return -ENOMEM; | ||
| 372 | |||
| 373 | *out++ = '\\'; | ||
| 374 | *out++ = 'x'; | ||
| 375 | *out++ = hex_asc_hi(c); | ||
| 376 | *out++ = hex_asc_lo(c); | ||
| 377 | |||
| 378 | *dst = out; | ||
| 379 | *osz -= 4; | ||
| 380 | |||
| 381 | return 1; | ||
| 382 | } | ||
| 383 | |||
| 384 | /** | ||
| 385 | * string_escape_mem - quote characters in the given memory buffer | ||
| 386 | * @src: source buffer (unescaped) | ||
| 387 | * @isz: source buffer size | ||
| 388 | * @dst: destination buffer (escaped) | ||
| 389 | * @osz: destination buffer size | ||
| 390 | * @flags: combination of the flags (bitwise OR): | ||
| 391 | * %ESCAPE_SPACE: | ||
| 392 | * '\f' - form feed | ||
| 393 | * '\n' - new line | ||
| 394 | * '\r' - carriage return | ||
| 395 | * '\t' - horizontal tab | ||
| 396 | * '\v' - vertical tab | ||
| 397 | * %ESCAPE_SPECIAL: | ||
| 398 | * '\\' - backslash | ||
| 399 | * '\a' - alert (BEL) | ||
| 400 | * '\e' - escape | ||
| 401 | * %ESCAPE_NULL: | ||
| 402 | * '\0' - null | ||
| 403 | * %ESCAPE_OCTAL: | ||
| 404 | * '\NNN' - byte with octal value NNN (3 digits) | ||
| 405 | * %ESCAPE_ANY: | ||
| 406 | * all previous together | ||
| 407 | * %ESCAPE_NP: | ||
| 408 | * escape only non-printable characters (checked by isprint) | ||
| 409 | * %ESCAPE_ANY_NP: | ||
| 410 | * all previous together | ||
| 411 | * %ESCAPE_HEX: | ||
| 412 | * '\xHH' - byte with hexadecimal value HH (2 digits) | ||
| 413 | * @esc: NULL-terminated string of characters any of which, if found in | ||
| 414 | * the source, has to be escaped | ||
| 415 | * | ||
| 416 | * Description: | ||
| 417 | * The process of escaping byte buffer includes several parts. They are applied | ||
| 418 | * in the following sequence. | ||
| 419 | * 1. The character is matched to the printable class, if asked, and in | ||
| 420 | * case of match it passes through to the output. | ||
| 421 | * 2. The character is not matched to the one from @esc string and thus | ||
| 422 | * must go as is to the output. | ||
| 423 | * 3. The character is checked if it falls into the class given by @flags. | ||
| 424 | * %ESCAPE_OCTAL and %ESCAPE_HEX are going last since they cover any | ||
| 425 | * character. Note that they actually can't go together, otherwise | ||
| 426 | * %ESCAPE_HEX will be ignored. | ||
| 427 | * | ||
| 428 | * Caller must provide valid source and destination pointers. Be aware that | ||
| 429 | * destination buffer will not be NULL-terminated, thus caller have to append | ||
| 430 | * it if needs. | ||
| 431 | * | ||
| 432 | * Return: | ||
| 433 | * The amount of the characters processed to the destination buffer, or | ||
| 434 | * %-ENOMEM if the size of buffer is not enough to put an escaped character is | ||
| 435 | * returned. | ||
| 436 | * | ||
| 437 | * Even in the case of error @dst pointer will be updated to point to the byte | ||
| 438 | * after the last processed character. | ||
| 439 | */ | ||
| 440 | int string_escape_mem(const char *src, size_t isz, char **dst, size_t osz, | ||
| 441 | unsigned int flags, const char *esc) | ||
| 442 | { | ||
| 443 | char *out = *dst, *p = out; | ||
| 444 | bool is_dict = esc && *esc; | ||
| 445 | int ret = 0; | ||
| 446 | |||
| 447 | while (isz--) { | ||
| 448 | unsigned char c = *src++; | ||
| 449 | |||
| 450 | /* | ||
| 451 | * Apply rules in the following sequence: | ||
| 452 | * - the character is printable, when @flags has | ||
| 453 | * %ESCAPE_NP bit set | ||
| 454 | * - the @esc string is supplied and does not contain a | ||
| 455 | * character under question | ||
| 456 | * - the character doesn't fall into a class of symbols | ||
| 457 | * defined by given @flags | ||
| 458 | * In these cases we just pass through a character to the | ||
| 459 | * output buffer. | ||
| 460 | */ | ||
| 461 | if ((flags & ESCAPE_NP && isprint(c)) || | ||
| 462 | (is_dict && !strchr(esc, c))) { | ||
| 463 | /* do nothing */ | ||
| 464 | } else { | ||
| 465 | if (flags & ESCAPE_SPACE) { | ||
| 466 | ret = escape_space(c, &p, &osz); | ||
| 467 | if (ret < 0) | ||
| 468 | break; | ||
| 469 | if (ret > 0) | ||
| 470 | continue; | ||
| 471 | } | ||
| 472 | |||
| 473 | if (flags & ESCAPE_SPECIAL) { | ||
| 474 | ret = escape_special(c, &p, &osz); | ||
| 475 | if (ret < 0) | ||
| 476 | break; | ||
| 477 | if (ret > 0) | ||
| 478 | continue; | ||
| 479 | } | ||
| 480 | |||
| 481 | if (flags & ESCAPE_NULL) { | ||
| 482 | ret = escape_null(c, &p, &osz); | ||
| 483 | if (ret < 0) | ||
| 484 | break; | ||
| 485 | if (ret > 0) | ||
| 486 | continue; | ||
| 487 | } | ||
| 488 | |||
| 489 | /* ESCAPE_OCTAL and ESCAPE_HEX always go last */ | ||
| 490 | if (flags & ESCAPE_OCTAL) { | ||
| 491 | ret = escape_octal(c, &p, &osz); | ||
| 492 | if (ret < 0) | ||
| 493 | break; | ||
| 494 | continue; | ||
| 495 | } | ||
| 496 | if (flags & ESCAPE_HEX) { | ||
| 497 | ret = escape_hex(c, &p, &osz); | ||
| 498 | if (ret < 0) | ||
| 499 | break; | ||
| 500 | continue; | ||
| 501 | } | ||
| 502 | } | ||
| 503 | |||
| 504 | ret = escape_passthrough(c, &p, &osz); | ||
| 505 | if (ret < 0) | ||
| 506 | break; | ||
| 507 | } | ||
| 508 | |||
| 509 | *dst = p; | ||
| 510 | |||
| 511 | if (ret < 0) | ||
| 512 | return ret; | ||
| 513 | |||
| 514 | return p - out; | ||
| 515 | } | ||
| 516 | EXPORT_SYMBOL(string_escape_mem); | ||
diff --git a/lib/test-string_helpers.c b/lib/test-string_helpers.c index 6ac48de04c0e..ab0d30e1e18f 100644 --- a/lib/test-string_helpers.c +++ b/lib/test-string_helpers.c | |||
| @@ -5,11 +5,32 @@ | |||
| 5 | 5 | ||
| 6 | #include <linux/init.h> | 6 | #include <linux/init.h> |
| 7 | #include <linux/kernel.h> | 7 | #include <linux/kernel.h> |
| 8 | #include <linux/slab.h> | ||
| 8 | #include <linux/module.h> | 9 | #include <linux/module.h> |
| 9 | #include <linux/random.h> | 10 | #include <linux/random.h> |
| 10 | #include <linux/string.h> | 11 | #include <linux/string.h> |
| 11 | #include <linux/string_helpers.h> | 12 | #include <linux/string_helpers.h> |
| 12 | 13 | ||
| 14 | static __init bool test_string_check_buf(const char *name, unsigned int flags, | ||
| 15 | char *in, size_t p, | ||
| 16 | char *out_real, size_t q_real, | ||
| 17 | char *out_test, size_t q_test) | ||
| 18 | { | ||
| 19 | if (q_real == q_test && !memcmp(out_test, out_real, q_test)) | ||
| 20 | return true; | ||
| 21 | |||
| 22 | pr_warn("Test '%s' failed: flags = %u\n", name, flags); | ||
| 23 | |||
| 24 | print_hex_dump(KERN_WARNING, "Input: ", DUMP_PREFIX_NONE, 16, 1, | ||
| 25 | in, p, true); | ||
| 26 | print_hex_dump(KERN_WARNING, "Expected: ", DUMP_PREFIX_NONE, 16, 1, | ||
| 27 | out_test, q_test, true); | ||
| 28 | print_hex_dump(KERN_WARNING, "Got: ", DUMP_PREFIX_NONE, 16, 1, | ||
| 29 | out_real, q_real, true); | ||
| 30 | |||
| 31 | return false; | ||
| 32 | } | ||
| 33 | |||
| 13 | struct test_string { | 34 | struct test_string { |
| 14 | const char *in; | 35 | const char *in; |
| 15 | const char *out; | 36 | const char *out; |
| @@ -39,12 +60,17 @@ static const struct test_string strings[] __initconst = { | |||
| 39 | }, | 60 | }, |
| 40 | }; | 61 | }; |
| 41 | 62 | ||
| 42 | static void __init test_string_unescape(unsigned int flags, bool inplace) | 63 | static void __init test_string_unescape(const char *name, unsigned int flags, |
| 64 | bool inplace) | ||
| 43 | { | 65 | { |
| 44 | char in[256]; | 66 | int q_real = 256; |
| 45 | char out_test[256]; | 67 | char *in = kmalloc(q_real, GFP_KERNEL); |
| 46 | char out_real[256]; | 68 | char *out_test = kmalloc(q_real, GFP_KERNEL); |
| 47 | int i, p = 0, q_test = 0, q_real = sizeof(out_real); | 69 | char *out_real = kmalloc(q_real, GFP_KERNEL); |
| 70 | int i, p = 0, q_test = 0; | ||
| 71 | |||
| 72 | if (!in || !out_test || !out_real) | ||
| 73 | goto out; | ||
| 48 | 74 | ||
| 49 | for (i = 0; i < ARRAY_SIZE(strings); i++) { | 75 | for (i = 0; i < ARRAY_SIZE(strings); i++) { |
| 50 | const char *s = strings[i].in; | 76 | const char *s = strings[i].in; |
| @@ -77,15 +103,225 @@ static void __init test_string_unescape(unsigned int flags, bool inplace) | |||
| 77 | q_real = string_unescape(in, out_real, q_real, flags); | 103 | q_real = string_unescape(in, out_real, q_real, flags); |
| 78 | } | 104 | } |
| 79 | 105 | ||
| 80 | if (q_real != q_test || memcmp(out_test, out_real, q_test)) { | 106 | test_string_check_buf(name, flags, in, p - 1, out_real, q_real, |
| 81 | pr_warn("Test failed: flags = %u\n", flags); | 107 | out_test, q_test); |
| 82 | print_hex_dump(KERN_WARNING, "Input: ", | 108 | out: |
| 83 | DUMP_PREFIX_NONE, 16, 1, in, p - 1, true); | 109 | kfree(out_real); |
| 84 | print_hex_dump(KERN_WARNING, "Expected: ", | 110 | kfree(out_test); |
| 85 | DUMP_PREFIX_NONE, 16, 1, out_test, q_test, true); | 111 | kfree(in); |
| 86 | print_hex_dump(KERN_WARNING, "Got: ", | 112 | } |
| 87 | DUMP_PREFIX_NONE, 16, 1, out_real, q_real, true); | 113 | |
| 114 | struct test_string_1 { | ||
| 115 | const char *out; | ||
| 116 | unsigned int flags; | ||
| 117 | }; | ||
| 118 | |||
| 119 | #define TEST_STRING_2_MAX_S1 32 | ||
| 120 | struct test_string_2 { | ||
| 121 | const char *in; | ||
| 122 | struct test_string_1 s1[TEST_STRING_2_MAX_S1]; | ||
| 123 | }; | ||
| 124 | |||
| 125 | #define TEST_STRING_2_DICT_0 NULL | ||
| 126 | static const struct test_string_2 escape0[] __initconst = {{ | ||
| 127 | .in = "\f\\ \n\r\t\v", | ||
| 128 | .s1 = {{ | ||
| 129 | .out = "\\f\\ \\n\\r\\t\\v", | ||
| 130 | .flags = ESCAPE_SPACE, | ||
| 131 | },{ | ||
| 132 | .out = "\\f\\134\\040\\n\\r\\t\\v", | ||
| 133 | .flags = ESCAPE_SPACE | ESCAPE_OCTAL, | ||
| 134 | },{ | ||
| 135 | .out = "\\f\\x5c\\x20\\n\\r\\t\\v", | ||
| 136 | .flags = ESCAPE_SPACE | ESCAPE_HEX, | ||
| 137 | },{ | ||
| 138 | /* terminator */ | ||
| 139 | }}, | ||
| 140 | },{ | ||
| 141 | .in = "\\h\\\"\a\e\\", | ||
| 142 | .s1 = {{ | ||
| 143 | .out = "\\\\h\\\\\"\\a\\e\\\\", | ||
| 144 | .flags = ESCAPE_SPECIAL, | ||
| 145 | },{ | ||
| 146 | .out = "\\\\\\150\\\\\\042\\a\\e\\\\", | ||
| 147 | .flags = ESCAPE_SPECIAL | ESCAPE_OCTAL, | ||
| 148 | },{ | ||
| 149 | .out = "\\\\\\x68\\\\\\x22\\a\\e\\\\", | ||
| 150 | .flags = ESCAPE_SPECIAL | ESCAPE_HEX, | ||
| 151 | },{ | ||
| 152 | /* terminator */ | ||
| 153 | }}, | ||
| 154 | },{ | ||
| 155 | .in = "\eb \\C\007\"\x90\r]", | ||
| 156 | .s1 = {{ | ||
| 157 | .out = "\eb \\C\007\"\x90\\r]", | ||
| 158 | .flags = ESCAPE_SPACE, | ||
| 159 | },{ | ||
| 160 | .out = "\\eb \\\\C\\a\"\x90\r]", | ||
| 161 | .flags = ESCAPE_SPECIAL, | ||
| 162 | },{ | ||
| 163 | .out = "\\eb \\\\C\\a\"\x90\\r]", | ||
| 164 | .flags = ESCAPE_SPACE | ESCAPE_SPECIAL, | ||
| 165 | },{ | ||
| 166 | .out = "\\033\\142\\040\\134\\103\\007\\042\\220\\015\\135", | ||
| 167 | .flags = ESCAPE_OCTAL, | ||
| 168 | },{ | ||
| 169 | .out = "\\033\\142\\040\\134\\103\\007\\042\\220\\r\\135", | ||
| 170 | .flags = ESCAPE_SPACE | ESCAPE_OCTAL, | ||
| 171 | },{ | ||
| 172 | .out = "\\e\\142\\040\\\\\\103\\a\\042\\220\\015\\135", | ||
| 173 | .flags = ESCAPE_SPECIAL | ESCAPE_OCTAL, | ||
| 174 | },{ | ||
| 175 | .out = "\\e\\142\\040\\\\\\103\\a\\042\\220\\r\\135", | ||
| 176 | .flags = ESCAPE_SPACE | ESCAPE_SPECIAL | ESCAPE_OCTAL, | ||
| 177 | },{ | ||
| 178 | .out = "\eb \\C\007\"\x90\r]", | ||
| 179 | .flags = ESCAPE_NP, | ||
| 180 | },{ | ||
| 181 | .out = "\eb \\C\007\"\x90\\r]", | ||
| 182 | .flags = ESCAPE_SPACE | ESCAPE_NP, | ||
| 183 | },{ | ||
| 184 | .out = "\\eb \\C\\a\"\x90\r]", | ||
| 185 | .flags = ESCAPE_SPECIAL | ESCAPE_NP, | ||
| 186 | },{ | ||
| 187 | .out = "\\eb \\C\\a\"\x90\\r]", | ||
| 188 | .flags = ESCAPE_SPACE | ESCAPE_SPECIAL | ESCAPE_NP, | ||
| 189 | },{ | ||
| 190 | .out = "\\033b \\C\\007\"\\220\\015]", | ||
| 191 | .flags = ESCAPE_OCTAL | ESCAPE_NP, | ||
| 192 | },{ | ||
| 193 | .out = "\\033b \\C\\007\"\\220\\r]", | ||
| 194 | .flags = ESCAPE_SPACE | ESCAPE_OCTAL | ESCAPE_NP, | ||
| 195 | },{ | ||
| 196 | .out = "\\eb \\C\\a\"\\220\\r]", | ||
| 197 | .flags = ESCAPE_SPECIAL | ESCAPE_SPACE | ESCAPE_OCTAL | | ||
| 198 | ESCAPE_NP, | ||
| 199 | },{ | ||
| 200 | .out = "\\x1bb \\C\\x07\"\\x90\\x0d]", | ||
| 201 | .flags = ESCAPE_NP | ESCAPE_HEX, | ||
| 202 | },{ | ||
| 203 | /* terminator */ | ||
| 204 | }}, | ||
| 205 | },{ | ||
| 206 | /* terminator */ | ||
| 207 | }}; | ||
| 208 | |||
| 209 | #define TEST_STRING_2_DICT_1 "b\\ \t\r" | ||
| 210 | static const struct test_string_2 escape1[] __initconst = {{ | ||
| 211 | .in = "\f\\ \n\r\t\v", | ||
| 212 | .s1 = {{ | ||
| 213 | .out = "\f\\134\\040\n\\015\\011\v", | ||
| 214 | .flags = ESCAPE_OCTAL, | ||
| 215 | },{ | ||
| 216 | .out = "\f\\x5c\\x20\n\\x0d\\x09\v", | ||
| 217 | .flags = ESCAPE_HEX, | ||
| 218 | },{ | ||
| 219 | /* terminator */ | ||
| 220 | }}, | ||
| 221 | },{ | ||
| 222 | .in = "\\h\\\"\a\e\\", | ||
| 223 | .s1 = {{ | ||
| 224 | .out = "\\134h\\134\"\a\e\\134", | ||
| 225 | .flags = ESCAPE_OCTAL, | ||
| 226 | },{ | ||
| 227 | /* terminator */ | ||
| 228 | }}, | ||
| 229 | },{ | ||
| 230 | .in = "\eb \\C\007\"\x90\r]", | ||
| 231 | .s1 = {{ | ||
| 232 | .out = "\e\\142\\040\\134C\007\"\x90\\015]", | ||
| 233 | .flags = ESCAPE_OCTAL, | ||
| 234 | },{ | ||
| 235 | /* terminator */ | ||
| 236 | }}, | ||
| 237 | },{ | ||
| 238 | /* terminator */ | ||
| 239 | }}; | ||
| 240 | |||
| 241 | static __init const char *test_string_find_match(const struct test_string_2 *s2, | ||
| 242 | unsigned int flags) | ||
| 243 | { | ||
| 244 | const struct test_string_1 *s1 = s2->s1; | ||
| 245 | unsigned int i; | ||
| 246 | |||
| 247 | if (!flags) | ||
| 248 | return s2->in; | ||
| 249 | |||
| 250 | /* Test cases are NULL-aware */ | ||
| 251 | flags &= ~ESCAPE_NULL; | ||
| 252 | |||
| 253 | /* ESCAPE_OCTAL has a higher priority */ | ||
| 254 | if (flags & ESCAPE_OCTAL) | ||
| 255 | flags &= ~ESCAPE_HEX; | ||
| 256 | |||
| 257 | for (i = 0; i < TEST_STRING_2_MAX_S1 && s1->out; i++, s1++) | ||
| 258 | if (s1->flags == flags) | ||
| 259 | return s1->out; | ||
| 260 | return NULL; | ||
| 261 | } | ||
| 262 | |||
| 263 | static __init void test_string_escape(const char *name, | ||
| 264 | const struct test_string_2 *s2, | ||
| 265 | unsigned int flags, const char *esc) | ||
| 266 | { | ||
| 267 | int q_real = 512; | ||
| 268 | char *out_test = kmalloc(q_real, GFP_KERNEL); | ||
| 269 | char *out_real = kmalloc(q_real, GFP_KERNEL); | ||
| 270 | char *in = kmalloc(256, GFP_KERNEL); | ||
| 271 | char *buf = out_real; | ||
| 272 | int p = 0, q_test = 0; | ||
| 273 | |||
| 274 | if (!out_test || !out_real || !in) | ||
| 275 | goto out; | ||
| 276 | |||
| 277 | for (; s2->in; s2++) { | ||
| 278 | const char *out; | ||
| 279 | int len; | ||
| 280 | |||
| 281 | /* NULL injection */ | ||
| 282 | if (flags & ESCAPE_NULL) { | ||
| 283 | in[p++] = '\0'; | ||
| 284 | out_test[q_test++] = '\\'; | ||
| 285 | out_test[q_test++] = '0'; | ||
| 286 | } | ||
| 287 | |||
| 288 | /* Don't try strings that have no output */ | ||
| 289 | out = test_string_find_match(s2, flags); | ||
| 290 | if (!out) | ||
| 291 | continue; | ||
| 292 | |||
| 293 | /* Copy string to in buffer */ | ||
| 294 | len = strlen(s2->in); | ||
| 295 | memcpy(&in[p], s2->in, len); | ||
| 296 | p += len; | ||
| 297 | |||
| 298 | /* Copy expected result for given flags */ | ||
| 299 | len = strlen(out); | ||
| 300 | memcpy(&out_test[q_test], out, len); | ||
| 301 | q_test += len; | ||
| 88 | } | 302 | } |
| 303 | |||
| 304 | q_real = string_escape_mem(in, p, &buf, q_real, flags, esc); | ||
| 305 | |||
| 306 | test_string_check_buf(name, flags, in, p, out_real, q_real, out_test, | ||
| 307 | q_test); | ||
| 308 | out: | ||
| 309 | kfree(in); | ||
| 310 | kfree(out_real); | ||
| 311 | kfree(out_test); | ||
| 312 | } | ||
| 313 | |||
| 314 | static __init void test_string_escape_nomem(void) | ||
| 315 | { | ||
| 316 | char *in = "\eb \\C\007\"\x90\r]"; | ||
| 317 | char out[64], *buf = out; | ||
| 318 | int rc = -ENOMEM, ret; | ||
| 319 | |||
| 320 | ret = string_escape_str_any_np(in, &buf, strlen(in), NULL); | ||
| 321 | if (ret == rc) | ||
| 322 | return; | ||
| 323 | |||
| 324 | pr_err("Test 'escape nomem' failed: got %d instead of %d\n", ret, rc); | ||
| 89 | } | 325 | } |
| 90 | 326 | ||
| 91 | static int __init test_string_helpers_init(void) | 327 | static int __init test_string_helpers_init(void) |
| @@ -94,8 +330,19 @@ static int __init test_string_helpers_init(void) | |||
| 94 | 330 | ||
| 95 | pr_info("Running tests...\n"); | 331 | pr_info("Running tests...\n"); |
| 96 | for (i = 0; i < UNESCAPE_ANY + 1; i++) | 332 | for (i = 0; i < UNESCAPE_ANY + 1; i++) |
| 97 | test_string_unescape(i, false); | 333 | test_string_unescape("unescape", i, false); |
| 98 | test_string_unescape(get_random_int() % (UNESCAPE_ANY + 1), true); | 334 | test_string_unescape("unescape inplace", |
| 335 | get_random_int() % (UNESCAPE_ANY + 1), true); | ||
| 336 | |||
| 337 | /* Without dictionary */ | ||
| 338 | for (i = 0; i < (ESCAPE_ANY_NP | ESCAPE_HEX) + 1; i++) | ||
| 339 | test_string_escape("escape 0", escape0, i, TEST_STRING_2_DICT_0); | ||
| 340 | |||
| 341 | /* With dictionary */ | ||
| 342 | for (i = 0; i < (ESCAPE_ANY_NP | ESCAPE_HEX) + 1; i++) | ||
| 343 | test_string_escape("escape 1", escape1, i, TEST_STRING_2_DICT_1); | ||
| 344 | |||
| 345 | test_string_escape_nomem(); | ||
| 99 | 346 | ||
| 100 | return -EINVAL; | 347 | return -EINVAL; |
| 101 | } | 348 | } |
diff --git a/lib/textsearch.c b/lib/textsearch.c index 0c7e9ab2d88f..0b79908dfe89 100644 --- a/lib/textsearch.c +++ b/lib/textsearch.c | |||
| @@ -249,9 +249,7 @@ EXPORT_SYMBOL(textsearch_find_continuous); | |||
| 249 | * @flags: search flags | 249 | * @flags: search flags |
| 250 | * | 250 | * |
| 251 | * Looks up the search algorithm module and creates a new textsearch | 251 | * Looks up the search algorithm module and creates a new textsearch |
| 252 | * configuration for the specified pattern. Upon completion all | 252 | * configuration for the specified pattern. |
| 253 | * necessary refcnts are held and the configuration must be put back | ||
| 254 | * using textsearch_put() after usage. | ||
| 255 | * | 253 | * |
| 256 | * Note: The format of the pattern may not be compatible between | 254 | * Note: The format of the pattern may not be compatible between |
| 257 | * the various search algorithms. | 255 | * the various search algorithms. |
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 @@ | |||
| 33 | #include <asm/page.h> /* for PAGE_SIZE */ | 33 | #include <asm/page.h> /* for PAGE_SIZE */ |
| 34 | #include <asm/sections.h> /* for dereference_function_descriptor() */ | 34 | #include <asm/sections.h> /* for dereference_function_descriptor() */ |
| 35 | 35 | ||
| 36 | #include <linux/string_helpers.h> | ||
| 36 | #include "kstrtox.h" | 37 | #include "kstrtox.h" |
| 37 | 38 | ||
| 38 | /** | 39 | /** |
| @@ -1101,6 +1102,62 @@ char *ip4_addr_string_sa(char *buf, char *end, const struct sockaddr_in *sa, | |||
| 1101 | } | 1102 | } |
| 1102 | 1103 | ||
| 1103 | static noinline_for_stack | 1104 | static noinline_for_stack |
| 1105 | char *escaped_string(char *buf, char *end, u8 *addr, struct printf_spec spec, | ||
| 1106 | const char *fmt) | ||
| 1107 | { | ||
| 1108 | bool found = true; | ||
| 1109 | int count = 1; | ||
| 1110 | unsigned int flags = 0; | ||
| 1111 | int len; | ||
| 1112 | |||
| 1113 | if (spec.field_width == 0) | ||
| 1114 | return buf; /* nothing to print */ | ||
| 1115 | |||
| 1116 | if (ZERO_OR_NULL_PTR(addr)) | ||
| 1117 | return string(buf, end, NULL, spec); /* NULL pointer */ | ||
| 1118 | |||
| 1119 | |||
| 1120 | do { | ||
| 1121 | switch (fmt[count++]) { | ||
| 1122 | case 'a': | ||
| 1123 | flags |= ESCAPE_ANY; | ||
| 1124 | break; | ||
| 1125 | case 'c': | ||
| 1126 | flags |= ESCAPE_SPECIAL; | ||
| 1127 | break; | ||
| 1128 | case 'h': | ||
| 1129 | flags |= ESCAPE_HEX; | ||
| 1130 | break; | ||
| 1131 | case 'n': | ||
| 1132 | flags |= ESCAPE_NULL; | ||
| 1133 | break; | ||
| 1134 | case 'o': | ||
| 1135 | flags |= ESCAPE_OCTAL; | ||
| 1136 | break; | ||
| 1137 | case 'p': | ||
| 1138 | flags |= ESCAPE_NP; | ||
| 1139 | break; | ||
| 1140 | case 's': | ||
| 1141 | flags |= ESCAPE_SPACE; | ||
| 1142 | break; | ||
| 1143 | default: | ||
| 1144 | found = false; | ||
| 1145 | break; | ||
| 1146 | } | ||
| 1147 | } while (found); | ||
| 1148 | |||
| 1149 | if (!flags) | ||
| 1150 | flags = ESCAPE_ANY_NP; | ||
| 1151 | |||
| 1152 | len = spec.field_width < 0 ? 1 : spec.field_width; | ||
| 1153 | |||
| 1154 | /* Ignore the error. We print as many characters as we can */ | ||
| 1155 | string_escape_mem(addr, len, &buf, end - buf, flags, NULL); | ||
| 1156 | |||
| 1157 | return buf; | ||
| 1158 | } | ||
| 1159 | |||
| 1160 | static noinline_for_stack | ||
| 1104 | char *uuid_string(char *buf, char *end, const u8 *addr, | 1161 | char *uuid_string(char *buf, char *end, const u8 *addr, |
| 1105 | struct printf_spec spec, const char *fmt) | 1162 | struct printf_spec spec, const char *fmt) |
| 1106 | { | 1163 | { |
| @@ -1221,6 +1278,17 @@ int kptr_restrict __read_mostly; | |||
| 1221 | * - '[Ii][4S][hnbl]' IPv4 addresses in host, network, big or little endian order | 1278 | * - '[Ii][4S][hnbl]' IPv4 addresses in host, network, big or little endian order |
| 1222 | * - 'I[6S]c' for IPv6 addresses printed as specified by | 1279 | * - 'I[6S]c' for IPv6 addresses printed as specified by |
| 1223 | * http://tools.ietf.org/html/rfc5952 | 1280 | * http://tools.ietf.org/html/rfc5952 |
| 1281 | * - 'E[achnops]' For an escaped buffer, where rules are defined by combination | ||
| 1282 | * of the following flags (see string_escape_mem() for the | ||
| 1283 | * details): | ||
| 1284 | * a - ESCAPE_ANY | ||
| 1285 | * c - ESCAPE_SPECIAL | ||
| 1286 | * h - ESCAPE_HEX | ||
| 1287 | * n - ESCAPE_NULL | ||
| 1288 | * o - ESCAPE_OCTAL | ||
| 1289 | * p - ESCAPE_NP | ||
| 1290 | * s - ESCAPE_SPACE | ||
| 1291 | * By default ESCAPE_ANY_NP is used. | ||
| 1224 | * - 'U' For a 16 byte UUID/GUID, it prints the UUID/GUID in the form | 1292 | * - 'U' For a 16 byte UUID/GUID, it prints the UUID/GUID in the form |
| 1225 | * "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" | 1293 | * "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" |
| 1226 | * Options for %pU are: | 1294 | * Options for %pU are: |
| @@ -1321,6 +1389,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, | |||
| 1321 | }} | 1389 | }} |
| 1322 | } | 1390 | } |
| 1323 | break; | 1391 | break; |
| 1392 | case 'E': | ||
| 1393 | return escaped_string(buf, end, ptr, spec, fmt); | ||
| 1324 | case 'U': | 1394 | case 'U': |
| 1325 | return uuid_string(buf, end, ptr, spec, fmt); | 1395 | return uuid_string(buf, end, ptr, spec, fmt); |
| 1326 | case 'V': | 1396 | case 'V': |
| @@ -1633,6 +1703,7 @@ qualifier: | |||
| 1633 | * %piS depending on sa_family of 'struct sockaddr *' print IPv4/IPv6 address | 1703 | * %piS depending on sa_family of 'struct sockaddr *' print IPv4/IPv6 address |
| 1634 | * %pU[bBlL] print a UUID/GUID in big or little endian using lower or upper | 1704 | * %pU[bBlL] print a UUID/GUID in big or little endian using lower or upper |
| 1635 | * case. | 1705 | * case. |
| 1706 | * %*pE[achnops] print an escaped buffer | ||
| 1636 | * %*ph[CDN] a variable-length hex string with a separator (supports up to 64 | 1707 | * %*ph[CDN] a variable-length hex string with a separator (supports up to 64 |
| 1637 | * bytes of the input) | 1708 | * bytes of the input) |
| 1638 | * %n is ignored | 1709 | * %n is ignored |
