aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-10-13 21:54:50 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-10-13 21:54:50 -0400
commitdfe2c6dcc8ca2cdc662d7c0473e9811b72ef3370 (patch)
tree9ed639a08c16322cdf136d576f42df5b97cd1549 /lib
parenta45d572841a24db02a62cf05e1157c35fdd3705b (diff)
parent64e455079e1bd7787cc47be30b7f601ce682a5f6 (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.debug2
-rw-r--r--lib/Makefile4
-rw-r--r--lib/dynamic_debug.c17
-rw-r--r--lib/prio_heap.c70
-rw-r--r--lib/string.c28
-rw-r--r--lib/string_helpers.c312
-rw-r--r--lib/test-string_helpers.c277
-rw-r--r--lib/textsearch.c4
-rw-r--r--lib/vsprintf.c71
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
1651config TEST_MODULE 1651config 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
31obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o 31obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o
32obj-y += kstrtox.o 32obj-y += kstrtox.o
33obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o 33obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
34obj-$(CONFIG_TEST_MODULE) += test_module.o 34obj-$(CONFIG_TEST_LKM) += test_module.o
35obj-$(CONFIG_TEST_USER_COPY) += test_user_copy.o 35obj-$(CONFIG_TEST_USER_COPY) += test_user_copy.o
36obj-$(CONFIG_TEST_BPF) += test_bpf.o 36obj-$(CONFIG_TEST_BPF) += test_bpf.o
37obj-$(CONFIG_TEST_FIRMWARE) += test_firmware.o 37obj-$(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 */
820static int ddebug_proc_open(struct inode *inode, struct file *file) 820static 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
840static const struct file_operations ddebug_proc_fops = { 827static 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
9int 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
21void heap_free(struct ptr_heap *heap)
22{
23 kfree(heap->ptrs);
24}
25
26void *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 */
37int strnicmp(const char *s1, const char *s2, size_t len) 37int 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}
59EXPORT_SYMBOL(strncasecmp);
60#endif
61#ifndef __HAVE_ARCH_STRNICMP
62#undef strnicmp
63int strnicmp(const char *s1, const char *s2, size_t len)
64{
65 return strncasecmp(s1, s2, len);
66}
59EXPORT_SYMBOL(strnicmp); 67EXPORT_SYMBOL(strnicmp);
60#endif 68#endif
61 69
@@ -73,20 +81,6 @@ int strcasecmp(const char *s1, const char *s2)
73EXPORT_SYMBOL(strcasecmp); 81EXPORT_SYMBOL(strcasecmp);
74#endif 82#endif
75 83
76#ifndef __HAVE_ARCH_STRNCASECMP
77int 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}
87EXPORT_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 */
171int string_unescape(char *src, char *dst, size_t size, unsigned int flags) 211int 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}
204EXPORT_SYMBOL(string_unescape); 244EXPORT_SYMBOL(string_unescape);
245
246static 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
261static 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
298static 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
329static 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
348static 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
366static 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 */
440int 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}
516EXPORT_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
14static __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
13struct test_string { 34struct 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
42static void __init test_string_unescape(unsigned int flags, bool inplace) 63static 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: ", 108out:
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
114struct test_string_1 {
115 const char *out;
116 unsigned int flags;
117};
118
119#define TEST_STRING_2_MAX_S1 32
120struct 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
126static 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"
210static 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
241static __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
263static __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);
308out:
309 kfree(in);
310 kfree(out_real);
311 kfree(out_test);
312}
313
314static __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
91static int __init test_string_helpers_init(void) 327static 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
1103static noinline_for_stack 1104static noinline_for_stack
1105char *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
1160static noinline_for_stack
1104char *uuid_string(char *buf, char *end, const u8 *addr, 1161char *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