From dabdb361633d93fd753157273a605a44bd5db557 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Wed, 8 Jul 2026 22:37:02 +0200 Subject: sh: clean up asm/string.h First, remove the !__KERNEL__ block, since U-Boot is always compiled with -D__KERNEL__. Second, remove the mention of the non-existing file arch/sh/lib/strcasecmp.c and the redundant declaration of strcasecmp() If sh did have a strcasecmp.c file, presumably the header would have had to #define __HAVE_ARCH_STRCASECMP. Third, remove the explicit #undefs of various __HAVE_ARCH_* and redundant declarations of standard functions, which are anyway declared in linux/string.h. In the linux source tree, those are all #defines, and indeed linux does have asm implementations of those functions. Reviewed-by: Simon Glass Signed-off-by: Rasmus Villemoes --- arch/sh/include/asm/string.h | 51 -------------------------------------------- 1 file changed, 51 deletions(-) diff --git a/arch/sh/include/asm/string.h b/arch/sh/include/asm/string.h index 999febcb6b7..12a9a8f796c 100644 --- a/arch/sh/include/asm/string.h +++ b/arch/sh/include/asm/string.h @@ -8,8 +8,6 @@ * from linux kernel code. */ -#ifdef __KERNEL__ /* only set these up for kernel code */ - #define __HAVE_ARCH_STRCPY static inline char *strcpy(char *__dest, const char *__src) { @@ -81,53 +79,4 @@ static inline int strcmp(const char *__cs, const char *__ct) return __res; } -#undef __HAVE_ARCH_STRNCMP -extern int strncmp(const char *__cs, const char *__ct, size_t __n); - -#undef __HAVE_ARCH_MEMSET -extern void *memset(void *__s, int __c, size_t __count); - -#undef __HAVE_ARCH_MEMCPY -extern void *memcpy(void *__to, __const__ void *__from, size_t __n); - -#undef __HAVE_ARCH_MEMMOVE -extern void *memmove(void *__dest, __const__ void *__src, size_t __n); - -#undef __HAVE_ARCH_MEMCHR -extern void *memchr(const void *__s, int __c, size_t __n); - -#undef __HAVE_ARCH_STRLEN -extern size_t strlen(const char *); - -/* arch/sh/lib/strcasecmp.c */ -extern int strcasecmp(const char *, const char *); - -#else /* KERNEL */ - -/* - * let user libraries deal with these, - * IMHO the kernel has no place defining these functions for user apps - */ - -#define __HAVE_ARCH_STRCPY 1 -#define __HAVE_ARCH_STRNCPY 1 -#define __HAVE_ARCH_STRCAT 1 -#define __HAVE_ARCH_STRNCAT 1 -#define __HAVE_ARCH_STRCMP 1 -#define __HAVE_ARCH_STRNCMP 1 -#define __HAVE_ARCH_STRNICMP 1 -#define __HAVE_ARCH_STRCHR 1 -#define __HAVE_ARCH_STRRCHR 1 -#define __HAVE_ARCH_STRSTR 1 -#define __HAVE_ARCH_STRLEN 1 -#define __HAVE_ARCH_STRNLEN 1 -#define __HAVE_ARCH_MEMSET 1 -#define __HAVE_ARCH_MEMCPY 1 -#define __HAVE_ARCH_MEMMOVE 1 -#define __HAVE_ARCH_MEMSCAN 1 -#define __HAVE_ARCH_MEMCMP 1 -#define __HAVE_ARCH_MEMCHR 1 -#define __HAVE_ARCH_STRTOK 1 - -#endif /* KERNEL */ #endif /* __ASM_SH_STRING_H */ -- cgit v1.3.1 From 210fedfcfc1a146faac67dddb3581c6b9dcd01b4 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Wed, 8 Jul 2026 22:37:03 +0200 Subject: string: correct prototype of strchrnul() Both glibc's (where this originated as a GNU extension) and the kernel's versions of strchrnul() return "char *", not "const char *". That also makes it consistent with the standard strchr() function. Reviewed-by: Simon Glass Signed-off-by: Rasmus Villemoes --- include/linux/string.h | 2 +- lib/string.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/linux/string.h b/include/linux/string.h index 850356d7c3f..488a459ed99 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -63,7 +63,7 @@ extern char * strchr(const char *,int); * @c: character to search for * Return: position of @c in @s, or end of @s if not found */ -const char *strchrnul(const char *s, int c); +char *strchrnul(const char *s, int c); #ifndef __HAVE_ARCH_STRRCHR extern char * strrchr(const char *,int); diff --git a/lib/string.c b/lib/string.c index 37ea8c29561..a76dcd48d20 100644 --- a/lib/string.c +++ b/lib/string.c @@ -263,12 +263,12 @@ char * strchr(const char * s, int c) } #endif -const char *strchrnul(const char *s, int c) +char *strchrnul(const char *s, int c) { for (; *s != (char)c; ++s) if (*s == '\0') break; - return s; + return (char *)s; } #ifndef __HAVE_ARCH_STRRCHR -- cgit v1.3.1 From 6b58f877bdd70003b6c57b540693c2e188b8cc8a Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Wed, 8 Jul 2026 22:37:04 +0200 Subject: string: correct documentation for strstr and strnstr The len parameter for strnstr() concerns the maximum size of the haystack to consider, not the length of the needle being searched for. strstr() obviously has no len parameter, so remove the copy-pasta. Reviewed-by: Simon Glass Signed-off-by: Rasmus Villemoes --- lib/string.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/string.c b/lib/string.c index a76dcd48d20..45f0f5f8d09 100644 --- a/lib/string.c +++ b/lib/string.c @@ -702,7 +702,7 @@ void *memdup(const void *src, size_t len) * * @s1: string to be searched * @s2: string to search for - * @len: maximum number of characters in s2 to consider + * @len: maximum number of characters in s1 to consider * * Return: pointer to the first occurrence or NULL */ @@ -728,7 +728,6 @@ char *strnstr(const char *s1, const char *s2, size_t len) * * @s1: string to be searched * @s2: string to search for - * @len: maximum number of characters in s2 to consider * * Return: pointer to the first occurrence or NULL */ -- cgit v1.3.1 From a31d9375dfbd7f0f4030c0b81f2030ff554529be Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Wed, 8 Jul 2026 22:37:05 +0200 Subject: string: remove unused strswab() function The last use of this function with rather peculiar semantics[*] vanished in 2021 with 0a527fda782 ("Fix IDE commands issued, fix endian issues, fix non MMIO"). It has no tests, and should a need for something similar ever appear, it is better done with some proper utf16le/utf16be/utf16 abstractions rather than cluttering code with '#ifdef __LITTLE_ENDIAN'. [*] The byte-swapping itself is weird enough. But why is an input string of odd length ok, while the empty string is not allowed? Reviewed-by: Simon Glass Signed-off-by: Rasmus Villemoes --- include/linux/string.h | 4 ---- lib/string.c | 28 ---------------------------- 2 files changed, 32 deletions(-) diff --git a/include/linux/string.h b/include/linux/string.h index 488a459ed99..5bcbf72a89b 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -107,10 +107,6 @@ extern char * strndup(const char *, size_t); extern const char *strdup_const(const char *s); extern void kfree_const(const void *x); -#ifndef __HAVE_ARCH_STRSWAB -extern char * strswab(const char *); -#endif - #ifndef __HAVE_ARCH_MEMSET extern void * memset(void *,int,__kernel_size_t); #endif diff --git a/lib/string.c b/lib/string.c index 45f0f5f8d09..82d0b6a9caa 100644 --- a/lib/string.c +++ b/lib/string.c @@ -503,34 +503,6 @@ char * strsep(char **s, const char *ct) } #endif -#ifndef __HAVE_ARCH_STRSWAB -/** - * strswab - swap adjacent even and odd bytes in %NUL-terminated string - * s: address of the string - * - * returns the address of the swapped string or NULL on error. If - * string length is odd, last byte is untouched. - */ -char *strswab(const char *s) -{ - char *p, *q; - - if ((NULL == s) || ('\0' == *s)) { - return (NULL); - } - - for (p=(char *)s, q=p+1; (*p != '\0') && (*q != '\0'); p+=2, q+=2) { - char tmp; - - tmp = *p; - *p = *q; - *q = tmp; - } - - return (char *) s; -} -#endif - #ifndef __HAVE_ARCH_MEMSET /** * memset - Fill a region of memory with the given value -- cgit v1.3.1 From 07fcb18623b4d4ad604668cfccb63890ce300ce5 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Wed, 8 Jul 2026 22:37:06 +0200 Subject: string: remove more pointless __HAVE_ARCH_STR* None of these six macros are defined by any architecture. Moreover, the ifndef guard only exists in either string.h or string.c, making them completely pointless. I'm not sure whether we have an explicit coding style discouraging the "extern" qualifier on function declarations, and string.h has a random mix of everything, but I can't leave it on strncasecmp() now that it will be immediately after strcasecmp() which doesn't have it. Reviewed-by: Simon Glass Signed-off-by: Rasmus Villemoes --- include/linux/string.h | 6 +----- lib/string.c | 8 -------- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/include/linux/string.h b/include/linux/string.h index 5bcbf72a89b..5e4594b19df 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -43,12 +43,8 @@ extern int strcmp(const char *,const char *); #ifndef __HAVE_ARCH_STRNCMP extern int strncmp(const char *,const char *,__kernel_size_t); #endif -#ifndef __HAVE_ARCH_STRCASECMP int strcasecmp(const char *s1, const char *s2); -#endif -#ifndef __HAVE_ARCH_STRNCASECMP -extern int strncasecmp(const char *s1, const char *s2, __kernel_size_t len); -#endif +int strncasecmp(const char *s1, const char *s2, __kernel_size_t len); #ifndef __HAVE_ARCH_STRCHR extern char * strchr(const char *,int); #endif diff --git a/lib/string.c b/lib/string.c index 82d0b6a9caa..20c934c18c3 100644 --- a/lib/string.c +++ b/lib/string.c @@ -399,7 +399,6 @@ void kfree_const(const void *x) } -#ifndef __HAVE_ARCH_STRSPN /** * strspn - Calculate the length of the initial substring of @s which only * contain letters in @accept @@ -424,9 +423,7 @@ size_t strspn(const char *s, const char *accept) return count; } -#endif -#ifndef __HAVE_ARCH_STRPBRK /** * strpbrk - Find the first occurrence of a set of characters * @cs: The string to be searched @@ -444,9 +441,7 @@ char * strpbrk(const char * cs,const char * ct) } return NULL; } -#endif -#ifndef __HAVE_ARCH_STRTOK /** * strtok - Split a string into tokens * @s: The string to be searched @@ -473,9 +468,7 @@ char * strtok(char * s,const char * ct) ___strtok = send; return (sbegin); } -#endif -#ifndef __HAVE_ARCH_STRSEP /** * strsep - Split a string into tokens * @s: The string to be searched @@ -501,7 +494,6 @@ char * strsep(char **s, const char *ct) return sbegin; } -#endif #ifndef __HAVE_ARCH_MEMSET /** -- cgit v1.3.1 From 13822d7f42706da356368f1389f8de10ac9869a5 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Wed, 8 Jul 2026 22:37:07 +0200 Subject: string: add strcasestr() While this is not likely needed by any "real" driver code, a later convenience addition to the "config" command will need this. As usual, the linker will throw it away if nothing actually uses it, so it should have no size impact when not used. Reviewed-by: Simon Glass Signed-off-by: Rasmus Villemoes --- include/linux/string.h | 1 + lib/string.c | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/include/linux/string.h b/include/linux/string.h index 5e4594b19df..986499dfc70 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -71,6 +71,7 @@ extern char * strstr(const char *,const char *); #ifndef __HAVE_ARCH_STRNSTR extern char *strnstr(const char *, const char *, size_t); #endif +char *strcasestr(const char *, const char *); #ifndef __HAVE_ARCH_STRLEN extern __kernel_size_t strlen(const char *); #endif diff --git a/lib/string.c b/lib/string.c index 20c934c18c3..dbf2ce340df 100644 --- a/lib/string.c +++ b/lib/string.c @@ -701,6 +701,33 @@ char *strstr(const char *s1, const char *s2) } #endif +/** + * strcasestr() - Case insensitive substring search + * + * @haystack: string to be searched + * @needle: string to search for + * + * Return: pointer to the first occurrence or NULL + * + * The case of both strings are ignored. + */ +char *strcasestr(const char *haystack, const char *needle) +{ + size_t l1, l2; + + l1 = strlen(haystack); + l2 = strlen(needle); + + while (l1 >= l2) { + if (!strncasecmp(haystack, needle, l2)) + return (char *)haystack; + haystack++; + l1--; + } + + return NULL; +} + #ifndef __HAVE_ARCH_MEMCHR /** * memchr - Find a character in an area of memory. -- cgit v1.3.1 From d589aa4417c57b2f02f674ccd0ebe4f2ba9bb221 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Wed, 8 Jul 2026 22:37:08 +0200 Subject: test: string: add test of new strcasestr() function Change the existing strstr() test a little so that the substring not found is "bits", i.e. one that is actually found when doing case insensitive search. Then copy all of lib_strstr(), adapt the expectation for the strcasestr(s1, s3) result, and add another "not found" case. Reviewed-by: Simon Glass Signed-off-by: Rasmus Villemoes --- test/lib/string.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/test/lib/string.c b/test/lib/string.c index db6f28dbfdf..d418a40c4d4 100644 --- a/test/lib/string.c +++ b/test/lib/string.c @@ -284,18 +284,36 @@ static int lib_strstr(struct unit_test_state *uts) { const char *s1 = "Itsy Bitsy Teenie Weenie"; const char *s2 = "eenie"; - const char *s3 = "easy"; + const char *s3 = "bits"; ut_asserteq_ptr(&s1[12], strstr(s1, s2)); ut_asserteq_ptr(&s1[13], strstr(&s1[3], &s2[1])); ut_assertnull(strstr(s1, s3)); - ut_asserteq_ptr(&s1[2], strstr(s1, &s3[2])); - ut_asserteq_ptr(&s1[8], strstr(&s1[5], &s3[2])); + ut_asserteq_ptr(&s1[1], strstr(s1, &s3[2])); + ut_asserteq_ptr(&s1[7], strstr(&s1[5], &s3[2])); return 0; } LIB_TEST(lib_strstr, 0); +/** lib_strcasestr() - unit test for strcasestr() */ +static int lib_strcasestr(struct unit_test_state *uts) +{ + const char *s1 = "Itsy Bitsy Teenie Weenie"; + const char *s2 = "eenie"; + const char *s3 = "bits"; + + ut_asserteq_ptr(&s1[12], strcasestr(s1, s2)); + ut_asserteq_ptr(&s1[13], strcasestr(&s1[3], &s2[1])); + ut_asserteq_ptr(&s1[5], strcasestr(s1, s3)); + ut_asserteq_ptr(&s1[1], strcasestr(s1, &s3[2])); + ut_asserteq_ptr(&s1[7], strcasestr(&s1[5], &s3[2])); + ut_assertnull(strcasestr(&s1[6], s3)); + + return 0; +} +LIB_TEST(lib_strcasestr, 0); + static int lib_strim(struct unit_test_state *uts) { char buf[BUFLEN], *p; -- cgit v1.3.1 From 304e18c9437550096e667adaa60acb6c4423d1f8 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Wed, 8 Jul 2026 22:37:09 +0200 Subject: cmd: config: allow simple filtering of output When doing development, it can be quite useful to enable CONFIG_CMD_CONFIG, so that one can always check whether a config knob one has just enabled has actually made it to target. Because sometimes, one doesn't flash the right binary, or maybe one has just done CONFIG_FOO=y in some config fragment, but that had no effect because one would also have to do CONFIG_BAR=y. However, 2400+ lines of text are rather hard to read through. One probably uses a terminal emulator with capturing enabled, but searching back through the capture file is a little tedious, and one easily ends up finding something that doesn't pertain to the most recent 'config' command invocation. So make it possible to limit the output to those lines containing a given string. Like the search functionality in menuconfig, make it case insensitive, because it is much more convenient to type "config pinctrl" than "config PINCTRL". Since enabling CONFIG_CMD_CONFIG by itself adds over 10K of data, and that increases with every U-Boot release even if one doesn't add any new features to one's own defconfig (because the .config grows lots of "is not set"), I don't see any point in guarding this by some CONFIG_CMD_CONFIG_GREP. Reviewed-by: Simon Glass Signed-off-by: Rasmus Villemoes --- cmd/config.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/cmd/config.c b/cmd/config.c index f0d2033c61f..22115e9b1da 100644 --- a/cmd/config.c +++ b/cmd/config.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "config_data_gz.h" #include "config_data_size.h" @@ -29,7 +30,23 @@ static int do_config(struct cmd_tbl *cmdtp, int flag, int argc, } dst[data_size] = 0; - puts(dst); + if (argc > 1) { + const char *s = argv[1]; + char *b = dst, *e = dst + data_size, *n; + + while (b < e) { + n = strchrnul(b, '\n'); + *n = '\0'; + + if (strcasestr(b, s)) { + puts(b); + puts("\n"); + } + b = n + 1; + } + } else { + puts(dst); + } free: free(dst); @@ -38,7 +55,10 @@ free: } U_BOOT_CMD( - config, 1, 1, do_config, + config, 2, 1, do_config, "print .config", - "" + "[str]\n" + "\n" + "When the optional argument is given, only lines containing\n" + "that string are printed. Matching is case-insensitive." ); -- cgit v1.3.1 From a2daa32913e6e96d47930e408d9b4f3b844bdfb7 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Wed, 8 Jul 2026 22:37:10 +0200 Subject: doc: document 'config' command Add a little documentation for the config command and its new ability to filter the output. Signed-off-by: Rasmus Villemoes Reviewed-by: Simon Glass --- doc/usage/cmd/config.rst | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 doc/usage/cmd/config.rst diff --git a/doc/usage/cmd/config.rst b/doc/usage/cmd/config.rst new file mode 100644 index 00000000000..bd8aa65ddbc --- /dev/null +++ b/doc/usage/cmd/config.rst @@ -0,0 +1,40 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. index:: + single: config (command) + +config command +============== + +Synopsis +-------- + +:: + + config [] + +Description +----------- + +The config command prints the `.config` file used when building U-Boot +to the console. Note that the `.config` file is usually several 1000 +lines long. + +If the optional argument is given, only lines containing that string +(case insensitively) are printed. That can be useful if one wants to +check whether a specific option is enabled, or just to limit the +output to the subsystem of interest. + +The `.config` file is stored inside the U-Boot binary in +gzip-compressed format. + +Examples +-------- + +.. code-block:: bash + + # Print the entire .config + config + + # Print all lines related to pinctrl + config pinctrl -- cgit v1.3.1 From d408eb2bc5a4675e11d7b77943553386d039bafc Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Wed, 8 Jul 2026 22:37:11 +0200 Subject: test: add test of 'config' command Add some test cases for the 'config' command, including the ability to filter the output. Signed-off-by: Rasmus Villemoes Reviewed-by: Simon Glass --- test/cmd/Makefile | 1 + test/cmd/config.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 test/cmd/config.c diff --git a/test/cmd/Makefile b/test/cmd/Makefile index 8d6932f1176..8d36463879d 100644 --- a/test/cmd/Makefile +++ b/test/cmd/Makefile @@ -17,6 +17,7 @@ ifdef CONFIG_CONSOLE_RECORD obj-$(CONFIG_CMD_ACPI) += acpi.o endif obj-$(CONFIG_CMD_BDI) += bdinfo.o +obj-$(CONFIG_CMD_CONFIG) += config.o obj-$(CONFIG_COREBOOT_SYSINFO) += coreboot.o obj-$(CONFIG_CMD_FDT) += fdt.o obj-$(CONFIG_CMD_HASH) += hash.o diff --git a/test/cmd/config.c b/test/cmd/config.c new file mode 100644 index 00000000000..5a48060801f --- /dev/null +++ b/test/cmd/config.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Tests for config command + */ + +#include +#include +#include + +static int cmd_test_config(struct unit_test_state *uts) +{ + ut_assertok(run_command("config", 0)); + ut_assert_skip_to_line("# Automatically generated file; DO NOT EDIT."); + ut_assert_skip_to_linen("# Compiler:"); + ut_assert_skip_to_line("CONFIG_CMD_CONFIG=y"); + + console_record_reset_enable(); + + ut_assertok(run_command("config cmd_config=y", 0)); + ut_assert_nextline("CONFIG_CMD_CONFIG=y"); + ut_assert_console_end(); + + ut_assertok(run_command("config 'this string never appears in .config'", 0)); + ut_assert_console_end(); + + return 0; +} +CMD_TEST(cmd_test_config, UTF_CONSOLE); -- cgit v1.3.1