bootconfig: Support mixing a value and subkeys under a key

Support mixing a value and subkeys under a key. Since kernel cmdline
options will support "aaa.bbb=value1 aaa.bbb.ccc=value2", it is
better that the bootconfig supports such configuration too.

Note that this does not change syntax itself but just accepts
mixed value and subkeys e.g.

key = value1
key.subkey = value2

But this is not accepted;

key {
 value1
 subkey = value2
}

That will make value1 as a subkey.

Also, the order of the value node under a key is fixed. If there
are a value and subkeys, the value is always the first child node
of the key. Thus if user specifies subkeys first, e.g.

key.subkey = value1
key = value2

In the program (and /proc/bootconfig), it will be shown as below

key = value2
key.subkey = value1

Link: https://lkml.kernel.org/r/162262194685.264090.7738574774030567419.stgit@devnote2

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
This commit is contained in:
Masami Hiramatsu 2021-06-02 17:19:07 +09:00 committed by Steven Rostedt (VMware)
parent ca24306d83
commit e5efaeb8a8
3 changed files with 115 additions and 29 deletions

View File

@ -80,6 +80,8 @@ static inline __init bool xbc_node_is_array(struct xbc_node *node)
* *
* Test the @node is a leaf key node which is a key node and has a value node * Test the @node is a leaf key node which is a key node and has a value node
* or no child. Returns true if it is a leaf node, or false if not. * or no child. Returns true if it is a leaf node, or false if not.
* Note that the leaf node can have subkey nodes in addition to the
* value node.
*/ */
static inline __init bool xbc_node_is_leaf(struct xbc_node *node) static inline __init bool xbc_node_is_leaf(struct xbc_node *node)
{ {
@ -129,6 +131,23 @@ static inline struct xbc_node * __init xbc_find_node(const char *key)
return xbc_node_find_child(NULL, key); return xbc_node_find_child(NULL, key);
} }
/**
* xbc_node_get_subkey() - Return the first subkey node if exists
* @node: Parent node
*
* Return the first subkey node of the @node. If the @node has no child
* or only value node, this will return NULL.
*/
static inline struct xbc_node * __init xbc_node_get_subkey(struct xbc_node *node)
{
struct xbc_node *child = xbc_node_get_child(node);
if (child && xbc_node_is_value(child))
return xbc_node_get_next(child);
else
return child;
}
/** /**
* xbc_array_for_each_value() - Iterate value nodes on an array * xbc_array_for_each_value() - Iterate value nodes on an array
* @anode: An XBC arraied value node * @anode: An XBC arraied value node
@ -149,11 +168,24 @@ static inline struct xbc_node * __init xbc_find_node(const char *key)
* @child: Iterated XBC node. * @child: Iterated XBC node.
* *
* Iterate child nodes of @parent. Each child nodes are stored to @child. * Iterate child nodes of @parent. Each child nodes are stored to @child.
* The @child can be mixture of a value node and subkey nodes.
*/ */
#define xbc_node_for_each_child(parent, child) \ #define xbc_node_for_each_child(parent, child) \
for (child = xbc_node_get_child(parent); child != NULL ; \ for (child = xbc_node_get_child(parent); child != NULL ; \
child = xbc_node_get_next(child)) child = xbc_node_get_next(child))
/**
* xbc_node_for_each_subkey() - Iterate child subkey nodes
* @parent: An XBC node.
* @child: Iterated XBC node.
*
* Iterate subkey nodes of @parent. Each child nodes are stored to @child.
* The @child is only the subkey node.
*/
#define xbc_node_for_each_subkey(parent, child) \
for (child = xbc_node_get_subkey(parent); child != NULL ; \
child = xbc_node_get_next(child))
/** /**
* xbc_node_for_each_array_value() - Iterate array entries of geven key * xbc_node_for_each_array_value() - Iterate array entries of geven key
* @node: An XBC node. * @node: An XBC node.

View File

@ -156,7 +156,7 @@ xbc_node_find_child(struct xbc_node *parent, const char *key)
struct xbc_node *node; struct xbc_node *node;
if (parent) if (parent)
node = xbc_node_get_child(parent); node = xbc_node_get_subkey(parent);
else else
node = xbc_root_node(); node = xbc_root_node();
@ -164,7 +164,7 @@ xbc_node_find_child(struct xbc_node *parent, const char *key)
if (!xbc_node_match_prefix(node, &key)) if (!xbc_node_match_prefix(node, &key))
node = xbc_node_get_next(node); node = xbc_node_get_next(node);
else if (*key != '\0') else if (*key != '\0')
node = xbc_node_get_child(node); node = xbc_node_get_subkey(node);
else else
break; break;
} }
@ -274,6 +274,8 @@ int __init xbc_node_compose_key_after(struct xbc_node *root,
struct xbc_node * __init xbc_node_find_next_leaf(struct xbc_node *root, struct xbc_node * __init xbc_node_find_next_leaf(struct xbc_node *root,
struct xbc_node *node) struct xbc_node *node)
{ {
struct xbc_node *next;
if (unlikely(!xbc_data)) if (unlikely(!xbc_data))
return NULL; return NULL;
@ -282,6 +284,13 @@ struct xbc_node * __init xbc_node_find_next_leaf(struct xbc_node *root,
if (!node) if (!node)
node = xbc_nodes; node = xbc_nodes;
} else { } else {
/* Leaf node may have a subkey */
next = xbc_node_get_subkey(node);
if (next) {
node = next;
goto found;
}
if (node == root) /* @root was a leaf, no child node. */ if (node == root) /* @root was a leaf, no child node. */
return NULL; return NULL;
@ -296,6 +305,7 @@ struct xbc_node * __init xbc_node_find_next_leaf(struct xbc_node *root,
node = xbc_node_get_next(node); node = xbc_node_get_next(node);
} }
found:
while (node && !xbc_node_is_leaf(node)) while (node && !xbc_node_is_leaf(node))
node = xbc_node_get_child(node); node = xbc_node_get_child(node);
@ -375,18 +385,20 @@ static inline __init struct xbc_node *xbc_last_child(struct xbc_node *node)
return node; return node;
} }
static struct xbc_node * __init xbc_add_sibling(char *data, u32 flag) static struct xbc_node * __init __xbc_add_sibling(char *data, u32 flag, bool head)
{ {
struct xbc_node *sib, *node = xbc_add_node(data, flag); struct xbc_node *sib, *node = xbc_add_node(data, flag);
if (node) { if (node) {
if (!last_parent) { if (!last_parent) {
/* Ignore @head in this case */
node->parent = XBC_NODE_MAX; node->parent = XBC_NODE_MAX;
sib = xbc_last_sibling(xbc_nodes); sib = xbc_last_sibling(xbc_nodes);
sib->next = xbc_node_index(node); sib->next = xbc_node_index(node);
} else { } else {
node->parent = xbc_node_index(last_parent); node->parent = xbc_node_index(last_parent);
if (!last_parent->child) { if (!last_parent->child || head) {
node->next = last_parent->child;
last_parent->child = xbc_node_index(node); last_parent->child = xbc_node_index(node);
} else { } else {
sib = xbc_node_get_child(last_parent); sib = xbc_node_get_child(last_parent);
@ -400,6 +412,16 @@ static struct xbc_node * __init xbc_add_sibling(char *data, u32 flag)
return node; return node;
} }
static inline struct xbc_node * __init xbc_add_sibling(char *data, u32 flag)
{
return __xbc_add_sibling(data, flag, false);
}
static inline struct xbc_node * __init xbc_add_head_sibling(char *data, u32 flag)
{
return __xbc_add_sibling(data, flag, true);
}
static inline __init struct xbc_node *xbc_add_child(char *data, u32 flag) static inline __init struct xbc_node *xbc_add_child(char *data, u32 flag)
{ {
struct xbc_node *node = xbc_add_sibling(data, flag); struct xbc_node *node = xbc_add_sibling(data, flag);
@ -568,8 +590,9 @@ static int __init __xbc_add_key(char *k)
node = find_match_node(xbc_nodes, k); node = find_match_node(xbc_nodes, k);
else { else {
child = xbc_node_get_child(last_parent); child = xbc_node_get_child(last_parent);
/* Since the value node is the first child, skip it. */
if (child && xbc_node_is_value(child)) if (child && xbc_node_is_value(child))
return xbc_parse_error("Subkey is mixed with value", k); child = xbc_node_get_next(child);
node = find_match_node(child, k); node = find_match_node(child, k);
} }
@ -612,27 +635,29 @@ static int __init xbc_parse_kv(char **k, char *v, int op)
if (ret) if (ret)
return ret; return ret;
child = xbc_node_get_child(last_parent);
if (child) {
if (xbc_node_is_key(child))
return xbc_parse_error("Value is mixed with subkey", v);
else if (op == '=')
return xbc_parse_error("Value is redefined", v);
}
c = __xbc_parse_value(&v, &next); c = __xbc_parse_value(&v, &next);
if (c < 0) if (c < 0)
return c; return c;
if (op == ':' && child) { child = xbc_node_get_child(last_parent);
xbc_init_node(child, v, XBC_VALUE); if (child && xbc_node_is_value(child)) {
} else { if (op == '=')
if (op == '+' && child) return xbc_parse_error("Value is redefined", v);
last_parent = xbc_last_child(child); if (op == ':') {
if (!xbc_add_sibling(v, XBC_VALUE)) unsigned short nidx = child->next;
return -ENOMEM;
}
xbc_init_node(child, v, XBC_VALUE);
child->next = nidx; /* keep subkeys */
goto array;
}
/* op must be '+' */
last_parent = xbc_last_child(child);
}
/* The value node should always be the first child */
if (!xbc_add_head_sibling(v, XBC_VALUE))
return -ENOMEM;
array:
if (c == ',') { /* Array */ if (c == ',') { /* Array */
c = xbc_parse_array(&next); c = xbc_parse_array(&next);
if (c < 0) if (c < 0)

View File

@ -35,30 +35,55 @@ static int xbc_show_value(struct xbc_node *node, bool semicolon)
static void xbc_show_compact_tree(void) static void xbc_show_compact_tree(void)
{ {
struct xbc_node *node, *cnode; struct xbc_node *node, *cnode = NULL, *vnode;
int depth = 0, i; int depth = 0, i;
node = xbc_root_node(); node = xbc_root_node();
while (node && xbc_node_is_key(node)) { while (node && xbc_node_is_key(node)) {
for (i = 0; i < depth; i++) for (i = 0; i < depth; i++)
printf("\t"); printf("\t");
cnode = xbc_node_get_child(node); if (!cnode)
cnode = xbc_node_get_child(node);
while (cnode && xbc_node_is_key(cnode) && !cnode->next) { while (cnode && xbc_node_is_key(cnode) && !cnode->next) {
vnode = xbc_node_get_child(cnode);
/*
* If @cnode has value and subkeys, this
* should show it as below.
*
* key(@node) {
* key(@cnode) = value;
* key(@cnode) {
* subkeys;
* }
* }
*/
if (vnode && xbc_node_is_value(vnode) && vnode->next)
break;
printf("%s.", xbc_node_get_data(node)); printf("%s.", xbc_node_get_data(node));
node = cnode; node = cnode;
cnode = xbc_node_get_child(node); cnode = vnode;
} }
if (cnode && xbc_node_is_key(cnode)) { if (cnode && xbc_node_is_key(cnode)) {
printf("%s {\n", xbc_node_get_data(node)); printf("%s {\n", xbc_node_get_data(node));
depth++; depth++;
node = cnode; node = cnode;
cnode = NULL;
continue; continue;
} else if (cnode && xbc_node_is_value(cnode)) { } else if (cnode && xbc_node_is_value(cnode)) {
printf("%s = ", xbc_node_get_data(node)); printf("%s = ", xbc_node_get_data(node));
xbc_show_value(cnode, true); xbc_show_value(cnode, true);
/*
* If @node has value and subkeys, continue
* looping on subkeys with same node.
*/
if (cnode->next) {
cnode = xbc_node_get_next(cnode);
continue;
}
} else { } else {
printf("%s;\n", xbc_node_get_data(node)); printf("%s;\n", xbc_node_get_data(node));
} }
cnode = NULL;
if (node->next) { if (node->next) {
node = xbc_node_get_next(node); node = xbc_node_get_next(node);
@ -70,10 +95,12 @@ static void xbc_show_compact_tree(void)
return; return;
if (!xbc_node_get_child(node)->next) if (!xbc_node_get_child(node)->next)
continue; continue;
depth--; if (depth) {
for (i = 0; i < depth; i++) depth--;
printf("\t"); for (i = 0; i < depth; i++)
printf("}\n"); printf("\t");
printf("}\n");
}
} }
node = xbc_node_get_next(node); node = xbc_node_get_next(node);
} }
@ -86,8 +113,10 @@ static void xbc_show_list(void)
const char *val; const char *val;
xbc_for_each_key_value(leaf, val) { xbc_for_each_key_value(leaf, val) {
if (xbc_node_compose_key(leaf, key, XBC_KEYLEN_MAX) < 0) if (xbc_node_compose_key(leaf, key, XBC_KEYLEN_MAX) < 0) {
fprintf(stderr, "Failed to compose key %d\n", ret);
break; break;
}
printf("%s = ", key); printf("%s = ", key);
if (!val || val[0] == '\0') { if (!val || val[0] == '\0') {
printf("\"\"\n"); printf("\"\"\n");