bootconfig: Terminate value search if it hits a newline

Terminate the value search for a key if it hits a newline and make
the value empty.

When we pass a bootconfig with an empty value terminated by the
newline, like below::

  foo =
  bar = value

Current bootconfig interprets it as a single entry::

  foo = "bar = value";

The Documentation/admin-guide/bootconfig.rst defines the value
itself is terminated by newline:

  The value has to be terminated by semi-colon (``;``) or newline (``\n``).

but it does not define when the value search is terminated.
This changes the behavior to be more line-oriented, so that it is
clearer in how it works.

- The value search of key-value pair will be terminated by a comment
  or newline.
- The value search of an array will continue beyond comments and
  newlines.

Thus, with this update, the above example is interpreted as::

  foo = "";
  bar = "value";

And the below example will cause a syntax error because "bar" is expected
as a key but it has ','.

  foo =
    bar, buz

According to this change, one wrong example config is updated.

Link: https://lore.kernel.org/all/177025238503.14982.17059549076175612447.stgit@devnote2/

Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Reviewed-by: Julius Werner <jwerner@chromium.org>
This commit is contained in:
Masami Hiramatsu (Google) 2026-02-05 09:46:25 +09:00
parent 18f7fcd5e6
commit 1cadf2819b
5 changed files with 44 additions and 18 deletions

View file

@ -20,18 +20,26 @@ Config File Syntax
The boot config syntax is a simple structured key-value. Each key consists
of dot-connected-words, and key and value are connected by ``=``. The value
has to be terminated by semi-colon (``;``) or newline (``\n``).
For array value, array entries are separated by comma (``,``). ::
KEY[.WORD[...]] = VALUE[, VALUE2[...]][;]
Unlike the kernel command line syntax, spaces are OK around the comma and ``=``.
string has to be terminated by the following delimiters described below.
Each key word must contain only alphabets, numbers, dash (``-``) or underscore
(``_``). And each value only contains printable characters or spaces except
for delimiters such as semi-colon (``;``), new-line (``\n``), comma (``,``),
hash (``#``) and closing brace (``}``).
If the ``=`` is followed by whitespace up to one of these delimiters, the
key is assigned an empty value.
For arrays, the array values are comma (``,``) separated, and comments and
line breaks with newline (``\n``) are allowed between array values for
readability. Thus the first entry of the array must be on the same line as
the key.::
KEY[.WORD[...]] = VALUE[, VALUE2[...]][;]
Unlike the kernel command line syntax, white spaces (including tabs) are
ignored around the comma and ``=``.
If you want to use those delimiters in a value, you can use either double-
quotes (``"VALUE"``) or single-quotes (``'VALUE'``) to quote it. Note that
you can not escape these quotes.
@ -138,8 +146,8 @@ This is parsed as below::
foo = value
bar = 1, 2, 3
Note that you can not put a comment between value and delimiter(``,`` or
``;``). This means following config has a syntax error ::
Note that you can NOT put a comment or a newline between value and delimiter
(``,`` or ``;``). This means following config has a syntax error ::
key = 1 # comment
,2

View file

@ -557,17 +557,13 @@ static int __init __xbc_close_brace(char *p)
/*
* Return delimiter or error, no node added. As same as lib/cmdline.c,
* you can use " around spaces, but can't escape " for value.
* *@__v must point real value string. (not including spaces before value.)
*/
static int __init __xbc_parse_value(char **__v, char **__n)
{
char *p, *v = *__v;
int c, quotes = 0;
v = skip_spaces(v);
while (*v == '#') {
v = skip_comment(v);
v = skip_spaces(v);
}
if (*v == '"' || *v == '\'') {
quotes = *v;
v++;
@ -617,6 +613,13 @@ static int __init xbc_parse_array(char **__v)
last_parent = xbc_node_get_child(last_parent);
do {
/* Search the next array value beyond comments and empty lines */
next = skip_spaces(*__v);
while (*next == '#') {
next = skip_comment(next);
next = skip_spaces(next);
}
*__v = next;
c = __xbc_parse_value(__v, &next);
if (c < 0)
return c;
@ -701,9 +704,17 @@ static int __init xbc_parse_kv(char **k, char *v, int op)
if (ret)
return ret;
c = __xbc_parse_value(&v, &next);
if (c < 0)
return c;
v = skip_spaces_until_newline(v);
/* If there is a comment, this has an empty value. */
if (*v == '#') {
next = skip_comment(v);
*v = '\0';
c = '\n';
} else {
c = __xbc_parse_value(&v, &next);
if (c < 0)
return c;
}
child = xbc_node_get_child(last_parent);
if (child && xbc_node_is_value(child)) {

View file

@ -0,0 +1,4 @@
# the first array value must be on the same line as the key
key = # comment
value1,
value2

View file

@ -0,0 +1,4 @@
# the first array value must be on the same line as the key
key =
value1,
value2

View file

@ -1,4 +1,3 @@
key = # comment
"value1", # comment1
key = "value1", # comment1
"value2" , # comment2
"value3"