It is not possible to put an array value with subkeys under a key node, because both of subkeys and the array elements are using "next" field of the xbc_node. Thus this changes the array values to use "child" field in the array case. The reason why split this change is to test it easily. Picking this up FROMLIST to get the fix ASAP. It is likely to be accepted upstream. Signed-off-by: Devin Moore <devinmoore@google.com> Link: https://lore.kernel.org/lkml/162262192121.264090.6540508908529705156.stgit@devnote2/ Bug: 183237066 Bug: 191737840 Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org> Change-Id: Iabd54cda32f6bde12297942d6b03bd2555e6eb0c
95 lines
1.9 KiB
C
95 lines
1.9 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* /proc/bootconfig - Extra boot configuration
|
|
*/
|
|
#include <linux/fs.h>
|
|
#include <linux/init.h>
|
|
#include <linux/printk.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/seq_file.h>
|
|
#include <linux/bootconfig.h>
|
|
#include <linux/slab.h>
|
|
|
|
static char *saved_boot_config;
|
|
|
|
static int boot_config_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
if (saved_boot_config)
|
|
seq_puts(m, saved_boot_config);
|
|
return 0;
|
|
}
|
|
|
|
/* Rest size of buffer */
|
|
#define rest(dst, end) ((end) > (dst) ? (end) - (dst) : 0)
|
|
|
|
/* Return the needed total length if @size is 0 */
|
|
static int __init copy_xbc_key_value_list(char *dst, size_t size)
|
|
{
|
|
struct xbc_node *leaf, *vnode;
|
|
char *key, *end = dst + size;
|
|
const char *val;
|
|
char q;
|
|
int ret = 0;
|
|
|
|
key = kzalloc(XBC_KEYLEN_MAX, GFP_KERNEL);
|
|
|
|
xbc_for_each_key_value(leaf, val) {
|
|
ret = xbc_node_compose_key(leaf, key, XBC_KEYLEN_MAX);
|
|
if (ret < 0)
|
|
break;
|
|
ret = snprintf(dst, rest(dst, end), "%s = ", key);
|
|
if (ret < 0)
|
|
break;
|
|
dst += ret;
|
|
vnode = xbc_node_get_child(leaf);
|
|
if (vnode) {
|
|
xbc_array_for_each_value(vnode, val) {
|
|
if (strchr(val, '"'))
|
|
q = '\'';
|
|
else
|
|
q = '"';
|
|
ret = snprintf(dst, rest(dst, end), "%c%s%c%s",
|
|
q, val, q, xbc_node_is_array(vnode) ? ", " : "\n");
|
|
if (ret < 0)
|
|
goto out;
|
|
dst += ret;
|
|
}
|
|
} else {
|
|
ret = snprintf(dst, rest(dst, end), "\"\"\n");
|
|
if (ret < 0)
|
|
break;
|
|
dst += ret;
|
|
}
|
|
}
|
|
out:
|
|
kfree(key);
|
|
|
|
return ret < 0 ? ret : dst - (end - size);
|
|
}
|
|
|
|
static int __init proc_boot_config_init(void)
|
|
{
|
|
int len;
|
|
|
|
len = copy_xbc_key_value_list(NULL, 0);
|
|
if (len < 0)
|
|
return len;
|
|
|
|
if (len > 0) {
|
|
saved_boot_config = kzalloc(len + 1, GFP_KERNEL);
|
|
if (!saved_boot_config)
|
|
return -ENOMEM;
|
|
|
|
len = copy_xbc_key_value_list(saved_boot_config, len + 1);
|
|
if (len < 0) {
|
|
kfree(saved_boot_config);
|
|
return len;
|
|
}
|
|
}
|
|
|
|
proc_create_single("bootconfig", 0, NULL, boot_config_proc_show);
|
|
|
|
return 0;
|
|
}
|
|
fs_initcall(proc_boot_config_init);
|