Merge tag 'bootconfig-v7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace

Pull bootconfig updates from Masami Hiramatsu:

 - bootconfig: move xbc_snprint_cmdline() to lib/bootconfig.c

   Move the xbc_snprint_cmdline() function and its buffer from
   main.c to the shared lib/bootconfig.c parser library so it
   can be reused by userspace tools.

 - render kernel.* subtree as cmdline string with -C

   Add a new -C option to print the kernel.* subtree as a flat
   command-line string at build time, allowing early parameter
   injection without runtime parsing.

* tag 'bootconfig-v7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
  tools/bootconfig: render kernel.* subtree as cmdline string with -C
  bootconfig: move xbc_snprint_cmdline() to lib/bootconfig.c
This commit is contained in:
Linus Torvalds committed 2026-06-16 17:29:24 +05:30
commit 4f7e89065e
4 files changed
+111 -53

No files matched your search

+3
View File
@@ -265,6 +265,9 @@ static inline struct xbc_node * __init xbc_node_get_subkey(struct xbc_node *node
int __init xbc_node_compose_key_after(struct xbc_node *root,
struct xbc_node *node, char *buf, size_t size);
/* Render key/value pairs under @root as a flat cmdline string */
int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root);
/**
* xbc_node_compose_key() - Compose full key string of the XBC node
* @node: An XBC node.
-45
View File
@@ -324,51 +324,6 @@ static void * __init get_boot_config_from_initrd(size_t *_size)
#ifdef CONFIG_BOOT_CONFIG
static char xbc_namebuf[XBC_KEYLEN_MAX] __initdata;
#define rest(dst, end) ((end) > (dst) ? (end) - (dst) : 0)
static int __init xbc_snprint_cmdline(char *buf, size_t size,
struct xbc_node *root)
{
struct xbc_node *knode, *vnode;
char *end = buf + size;
const char *val, *q;
int ret;
xbc_node_for_each_key_value(root, knode, val) {
ret = xbc_node_compose_key_after(root, knode,
xbc_namebuf, XBC_KEYLEN_MAX);
if (ret < 0)
return ret;
vnode = xbc_node_get_child(knode);
if (!vnode) {
ret = snprintf(buf, rest(buf, end), "%s ", xbc_namebuf);
if (ret < 0)
return ret;
buf += ret;
continue;
}
xbc_array_for_each_value(vnode, val) {
/*
* For prettier and more readable /proc/cmdline, only
* quote the value when necessary, i.e. when it contains
* whitespace.
*/
q = strpbrk(val, " \t\r\n") ? "\"" : "";
ret = snprintf(buf, rest(buf, end), "%s=%s%s%s ",
xbc_namebuf, q, val, q);
if (ret < 0)
return ret;
buf += ret;
}
}
return buf - (end - size);
}
#undef rest
/* Make an extra command line under given key word */
static char * __init xbc_make_cmdline(const char *key)
{
+56
View File
@@ -408,6 +408,62 @@ const char * __init xbc_node_find_next_key_value(struct xbc_node *root,
return ""; /* No value key */
}
static char xbc_namebuf[XBC_KEYLEN_MAX] __initdata;
#define rest(dst, end) ((end) > (dst) ? (end) - (dst) : 0)
/**
* xbc_snprint_cmdline() - Render bootconfig keys under @root as a cmdline string
* @buf: Destination buffer (may be NULL when @size is 0 to query the length)
* @size: Size of @buf in bytes
* @root: Subtree root whose key=value pairs should be rendered
*
* Walk all key/value pairs under @root and emit them as a space-separated
* cmdline string into @buf. Values containing whitespace are quoted with
* double quotes. Returns the number of bytes that would be written if @buf
* were large enough (matching snprintf semantics), or a negative errno on
* failure.
*/
int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root)
{
struct xbc_node *knode, *vnode;
char *end = buf + size;
const char *val, *q;
int ret;
xbc_node_for_each_key_value(root, knode, val) {
ret = xbc_node_compose_key_after(root, knode,
xbc_namebuf, XBC_KEYLEN_MAX);
if (ret < 0)
return ret;
vnode = xbc_node_get_child(knode);
if (!vnode) {
ret = snprintf(buf, rest(buf, end), "%s ", xbc_namebuf);
if (ret < 0)
return ret;
buf += ret;
continue;
}
xbc_array_for_each_value(vnode, val) {
/*
* For prettier and more readable /proc/cmdline, only
* quote the value when necessary, i.e. when it contains
* whitespace.
*/
q = strpbrk(val, " \t\r\n") ? "\"" : "";
ret = snprintf(buf, rest(buf, end), "%s=%s%s%s ",
xbc_namebuf, q, val, q);
if (ret < 0)
return ret;
buf += ret;
}
}
return buf - (end - size);
}
#undef rest
/* XBC parse and tree build */
static int __init xbc_init_node(struct xbc_node *node, char *data, uint16_t flag)
+52 -8
View File
@@ -286,7 +286,41 @@ static int init_xbc_with_error(char *buf, int len)
return ret;
}
static int show_xbc(const char *path, bool list)
static int show_xbc_kernel_cmdline(void)
{
struct xbc_node *root;
char *buf = NULL;
int len, ret;
root = xbc_find_node("kernel");
if (!root)
return 0; /* no kernel.* keys: emit empty output */
len = xbc_snprint_cmdline(NULL, 0, root);
if (len < 0) {
pr_err("Failed to size cmdline output: %d\n", len);
return len;
}
if (len == 0)
return 0;
buf = malloc(len + 1);
if (!buf)
return -ENOMEM;
ret = xbc_snprint_cmdline(buf, len + 1, root);
if (ret < 0) {
pr_err("Failed to render cmdline output: %d\n", ret);
free(buf);
return ret;
}
fputs(buf, stdout);
free(buf);
return 0;
}
static int show_xbc(const char *path, bool list, bool render_cmdline)
{
int ret, fd;
char *buf = NULL;
@@ -322,11 +356,14 @@ static int show_xbc(const char *path, bool list)
if (init_xbc_with_error(buf, ret) < 0)
goto out;
}
if (list)
if (render_cmdline)
ret = show_xbc_kernel_cmdline();
else if (list)
xbc_show_list();
else
xbc_show_compact_tree();
ret = 0;
if (ret > 0)
ret = 0;
out:
free(buf);
@@ -488,7 +525,10 @@ static int usage(void)
" Options:\n"
" -a <config>: Apply boot config to initrd\n"
" -d : Delete boot config file from initrd\n"
" -l : list boot config in initrd or file\n\n"
" -l : list boot config in initrd or file\n"
" -C : render the kernel.* subtree as a flat cmdline\n"
" string (suitable for embedding in a kernel image)\n"
" and print it to stdout\n\n"
" If no option is given, show the bootconfig in the given file.\n");
return -1;
}
@@ -497,10 +537,11 @@ int main(int argc, char **argv)
{
char *path = NULL;
char *apply = NULL;
bool render_cmdline = false;
bool delete = false, list = false;
int opt;
while ((opt = getopt(argc, argv, "hda:l")) != -1) {
while ((opt = getopt(argc, argv, "hda:lC")) != -1) {
switch (opt) {
case 'd':
delete = true;
@@ -511,14 +552,17 @@ int main(int argc, char **argv)
case 'l':
list = true;
break;
case 'C':
render_cmdline = true;
break;
case 'h':
default:
return usage();
}
}
if ((apply && delete) || (delete && list) || (apply && list)) {
pr_err("Error: You can give one of -a, -d or -l at once.\n");
if ((!!apply + !!delete + !!list + !!render_cmdline) > 1) {
pr_err("Error: You can give one of -a, -d, -l or -C at once.\n");
return usage();
}
@@ -534,5 +578,5 @@ int main(int argc, char **argv)
else if (delete)
return delete_xbc(path);
return show_xbc(path, list);
return show_xbc(path, list, render_cmdline);
}