Commit 89b74cac authored by Masami Hiramatsu's avatar Masami Hiramatsu Committed by Steven Rostedt (VMware)

tools/bootconfig: Show line and column in parse error

Show line and column when we got a parse error in bootconfig tool.
Current lib/bootconfig shows the parse error with byte offset, but
that is not human readable.
This makes xbc_init() not showing error message itself but able to
pass the error message and position to caller, so that the caller
can decode it and show the error message with line number and columns.

With this patch, bootconfig tool shows an error with line:column as
below.

  $ cat samples/bad-dotword.bconf
  # do not start keyword with .
  key {
    .word = 1
  }
  $ ./bootconfig -a samples/bad-dotword.bconf initrd
  Parse Error: Invalid keyword at 3:3

Link: http://lkml.kernel.org/r/158323469002.10560.4023923847704522760.stgit@devnote2Signed-off-by: default avatarMasami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: default avatarSteven Rostedt (VMware) <rostedt@goodmis.org>
parent 306b69dc
...@@ -216,7 +216,8 @@ static inline int __init xbc_node_compose_key(struct xbc_node *node, ...@@ -216,7 +216,8 @@ static inline int __init xbc_node_compose_key(struct xbc_node *node,
} }
/* XBC node initializer */ /* XBC node initializer */
int __init xbc_init(char *buf); int __init xbc_init(char *buf, const char **emsg, int *epos);
/* XBC cleanup data structures */ /* XBC cleanup data structures */
void __init xbc_destroy_all(void); void __init xbc_destroy_all(void);
......
...@@ -353,6 +353,8 @@ static int __init bootconfig_params(char *param, char *val, ...@@ -353,6 +353,8 @@ static int __init bootconfig_params(char *param, char *val,
static void __init setup_boot_config(const char *cmdline) static void __init setup_boot_config(const char *cmdline)
{ {
static char tmp_cmdline[COMMAND_LINE_SIZE] __initdata; static char tmp_cmdline[COMMAND_LINE_SIZE] __initdata;
const char *msg;
int pos;
u32 size, csum; u32 size, csum;
char *data, *copy; char *data, *copy;
u32 *hdr; u32 *hdr;
...@@ -400,10 +402,14 @@ static void __init setup_boot_config(const char *cmdline) ...@@ -400,10 +402,14 @@ static void __init setup_boot_config(const char *cmdline)
memcpy(copy, data, size); memcpy(copy, data, size);
copy[size] = '\0'; copy[size] = '\0';
ret = xbc_init(copy); ret = xbc_init(copy, &msg, &pos);
if (ret < 0) if (ret < 0) {
pr_err("Failed to parse bootconfig\n"); if (pos < 0)
else { pr_err("Failed to init bootconfig: %s.\n", msg);
else
pr_err("Failed to parse bootconfig: %s at %d.\n",
msg, pos);
} else {
pr_info("Load bootconfig: %d bytes %d nodes\n", size, ret); pr_info("Load bootconfig: %d bytes %d nodes\n", size, ret);
/* keys starting with "kernel." are passed via cmdline */ /* keys starting with "kernel." are passed via cmdline */
extra_command_line = xbc_make_cmdline("kernel"); extra_command_line = xbc_make_cmdline("kernel");
......
...@@ -29,12 +29,14 @@ static int xbc_node_num __initdata; ...@@ -29,12 +29,14 @@ static int xbc_node_num __initdata;
static char *xbc_data __initdata; static char *xbc_data __initdata;
static size_t xbc_data_size __initdata; static size_t xbc_data_size __initdata;
static struct xbc_node *last_parent __initdata; static struct xbc_node *last_parent __initdata;
static const char *xbc_err_msg __initdata;
static int xbc_err_pos __initdata;
static int __init xbc_parse_error(const char *msg, const char *p) static int __init xbc_parse_error(const char *msg, const char *p)
{ {
int pos = p - xbc_data; xbc_err_msg = msg;
xbc_err_pos = (int)(p - xbc_data);
pr_err("Parse error at pos %d: %s\n", pos, msg);
return -EINVAL; return -EINVAL;
} }
...@@ -738,33 +740,44 @@ void __init xbc_destroy_all(void) ...@@ -738,33 +740,44 @@ void __init xbc_destroy_all(void)
/** /**
* xbc_init() - Parse given XBC file and build XBC internal tree * xbc_init() - Parse given XBC file and build XBC internal tree
* @buf: boot config text * @buf: boot config text
* @emsg: A pointer of const char * to store the error message
* @epos: A pointer of int to store the error position
* *
* This parses the boot config text in @buf. @buf must be a * This parses the boot config text in @buf. @buf must be a
* null terminated string and smaller than XBC_DATA_MAX. * null terminated string and smaller than XBC_DATA_MAX.
* Return the number of stored nodes (>0) if succeeded, or -errno * Return the number of stored nodes (>0) if succeeded, or -errno
* if there is any error. * if there is any error.
* In error cases, @emsg will be updated with an error message and
* @epos will be updated with the error position which is the byte offset
* of @buf. If the error is not a parser error, @epos will be -1.
*/ */
int __init xbc_init(char *buf) int __init xbc_init(char *buf, const char **emsg, int *epos)
{ {
char *p, *q; char *p, *q;
int ret, c; int ret, c;
if (epos)
*epos = -1;
if (xbc_data) { if (xbc_data) {
pr_err("Error: bootconfig is already initialized.\n"); if (emsg)
*emsg = "Bootconfig is already initialized";
return -EBUSY; return -EBUSY;
} }
ret = strlen(buf); ret = strlen(buf);
if (ret > XBC_DATA_MAX - 1 || ret == 0) { if (ret > XBC_DATA_MAX - 1 || ret == 0) {
pr_err("Error: Config data is %s.\n", if (emsg)
ret ? "too big" : "empty"); *emsg = ret ? "Config data is too big" :
"Config data is empty";
return -ERANGE; return -ERANGE;
} }
xbc_nodes = memblock_alloc(sizeof(struct xbc_node) * XBC_NODE_MAX, xbc_nodes = memblock_alloc(sizeof(struct xbc_node) * XBC_NODE_MAX,
SMP_CACHE_BYTES); SMP_CACHE_BYTES);
if (!xbc_nodes) { if (!xbc_nodes) {
pr_err("Failed to allocate memory for bootconfig nodes.\n"); if (emsg)
*emsg = "Failed to allocate bootconfig nodes";
return -ENOMEM; return -ENOMEM;
} }
memset(xbc_nodes, 0, sizeof(struct xbc_node) * XBC_NODE_MAX); memset(xbc_nodes, 0, sizeof(struct xbc_node) * XBC_NODE_MAX);
...@@ -814,9 +827,13 @@ int __init xbc_init(char *buf) ...@@ -814,9 +827,13 @@ int __init xbc_init(char *buf)
if (!ret) if (!ret)
ret = xbc_verify_tree(); ret = xbc_verify_tree();
if (ret < 0) if (ret < 0) {
if (epos)
*epos = xbc_err_pos;
if (emsg)
*emsg = xbc_err_msg;
xbc_destroy_all(); xbc_destroy_all();
else } else
ret = xbc_node_num; ret = xbc_node_num;
return ret; return ret;
......
...@@ -130,6 +130,7 @@ int load_xbc_from_initrd(int fd, char **buf) ...@@ -130,6 +130,7 @@ int load_xbc_from_initrd(int fd, char **buf)
int ret; int ret;
u32 size = 0, csum = 0, rcsum; u32 size = 0, csum = 0, rcsum;
char magic[BOOTCONFIG_MAGIC_LEN]; char magic[BOOTCONFIG_MAGIC_LEN];
const char *msg;
ret = fstat(fd, &stat); ret = fstat(fd, &stat);
if (ret < 0) if (ret < 0)
...@@ -182,10 +183,12 @@ int load_xbc_from_initrd(int fd, char **buf) ...@@ -182,10 +183,12 @@ int load_xbc_from_initrd(int fd, char **buf)
return -EINVAL; return -EINVAL;
} }
ret = xbc_init(*buf); ret = xbc_init(*buf, &msg, NULL);
/* Wrong data */ /* Wrong data */
if (ret < 0) if (ret < 0) {
pr_err("parse error: %s.\n", msg);
return ret; return ret;
}
return size; return size;
} }
...@@ -244,11 +247,34 @@ int delete_xbc(const char *path) ...@@ -244,11 +247,34 @@ int delete_xbc(const char *path)
return ret; return ret;
} }
static void show_xbc_error(const char *data, const char *msg, int pos)
{
int lin = 1, col, i;
if (pos < 0) {
pr_err("Error: %s.\n", msg);
return;
}
/* Note that pos starts from 0 but lin and col should start from 1. */
col = pos + 1;
for (i = 0; i < pos; i++) {
if (data[i] == '\n') {
lin++;
col = pos - i;
}
}
pr_err("Parse Error: %s at %d:%d\n", msg, lin, col);
}
int apply_xbc(const char *path, const char *xbc_path) int apply_xbc(const char *path, const char *xbc_path)
{ {
u32 size, csum; u32 size, csum;
char *buf, *data; char *buf, *data;
int ret, fd; int ret, fd;
const char *msg;
int pos;
ret = load_xbc_file(xbc_path, &buf); ret = load_xbc_file(xbc_path, &buf);
if (ret < 0) { if (ret < 0) {
...@@ -267,11 +293,12 @@ int apply_xbc(const char *path, const char *xbc_path) ...@@ -267,11 +293,12 @@ int apply_xbc(const char *path, const char *xbc_path)
*(u32 *)(data + size + 4) = csum; *(u32 *)(data + size + 4) = csum;
/* Check the data format */ /* Check the data format */
ret = xbc_init(buf); ret = xbc_init(buf, &msg, &pos);
if (ret < 0) { if (ret < 0) {
pr_err("Failed to parse %s: %d\n", xbc_path, ret); show_xbc_error(data, msg, pos);
free(data); free(data);
free(buf); free(buf);
return ret; return ret;
} }
printf("Apply %s to %s\n", xbc_path, path); printf("Apply %s to %s\n", xbc_path, path);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment