diff options
Diffstat (limited to 'tools/bootconfig')
24 files changed, 211 insertions, 53 deletions
diff --git a/tools/bootconfig/Makefile b/tools/bootconfig/Makefile index 566c3e0ee561..90eb47c9d8de 100644 --- a/tools/bootconfig/Makefile +++ b/tools/bootconfig/Makefile @@ -10,7 +10,7 @@ srctree := $(patsubst %/,%,$(dir $(srctree))) endif LIBSRC = $(srctree)/lib/bootconfig.c $(srctree)/include/linux/bootconfig.h -CFLAGS = -Wall -g -I$(CURDIR)/include +override CFLAGS += -Wall -g -I$(CURDIR)/include ALL_TARGETS := bootconfig ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS)) @@ -18,7 +18,7 @@ ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS)) all: $(ALL_PROGRAMS) test $(OUTPUT)bootconfig: main.c include/linux/bootconfig.h $(LIBSRC) - $(CC) $(filter %.c,$^) $(CFLAGS) -o $@ + $(CC) $(filter %.c,$^) $(CFLAGS) $(LDFLAGS) -o $@ test: $(ALL_PROGRAMS) test-bootconfig.sh ./test-bootconfig.sh $(OUTPUT) diff --git a/tools/bootconfig/main.c b/tools/bootconfig/main.c index 8a48cc2536f5..7dc9fff9b637 100644 --- a/tools/bootconfig/main.c +++ b/tools/bootconfig/main.c @@ -11,11 +11,16 @@ #include <string.h> #include <errno.h> #include <endian.h> +#include <assert.h> #include <linux/bootconfig.h> #define pr_err(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__) +/* Bootconfig footer is [size][csum][BOOTCONFIG_MAGIC]. */ +#define BOOTCONFIG_FOOTER_SIZE \ + (sizeof(uint32_t) * 2 + BOOTCONFIG_MAGIC_LEN) + static int xbc_show_value(struct xbc_node *node, bool semicolon) { const char *val, *eol; @@ -157,8 +162,11 @@ static int load_xbc_file(const char *path, char **buf) if (fd < 0) return -errno; ret = fstat(fd, &stat); - if (ret < 0) - return -errno; + if (ret < 0) { + ret = -errno; + close(fd); + return ret; + } ret = load_xbc_fd(fd, buf, stat.st_size); @@ -185,10 +193,10 @@ static int load_xbc_from_initrd(int fd, char **buf) if (ret < 0) return -errno; - if (stat.st_size < 8 + BOOTCONFIG_MAGIC_LEN) + if (stat.st_size < BOOTCONFIG_FOOTER_SIZE) return 0; - if (lseek(fd, -BOOTCONFIG_MAGIC_LEN, SEEK_END) < 0) + if (lseek(fd, -(off_t)BOOTCONFIG_MAGIC_LEN, SEEK_END) < 0) return pr_errno("Failed to lseek for magic", -errno); if (read(fd, magic, BOOTCONFIG_MAGIC_LEN) < 0) @@ -198,7 +206,7 @@ static int load_xbc_from_initrd(int fd, char **buf) if (memcmp(magic, BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_LEN) != 0) return 0; - if (lseek(fd, -(8 + BOOTCONFIG_MAGIC_LEN), SEEK_END) < 0) + if (lseek(fd, -(off_t)BOOTCONFIG_FOOTER_SIZE, SEEK_END) < 0) return pr_errno("Failed to lseek for size", -errno); if (read(fd, &size, sizeof(uint32_t)) < 0) @@ -210,12 +218,12 @@ static int load_xbc_from_initrd(int fd, char **buf) csum = le32toh(csum); /* Wrong size error */ - if (stat.st_size < size + 8 + BOOTCONFIG_MAGIC_LEN) { + if (stat.st_size < size + BOOTCONFIG_FOOTER_SIZE) { pr_err("bootconfig size is too big\n"); return -E2BIG; } - if (lseek(fd, stat.st_size - (size + 8 + BOOTCONFIG_MAGIC_LEN), + if (lseek(fd, stat.st_size - (size + BOOTCONFIG_FOOTER_SIZE), SEEK_SET) < 0) return pr_errno("Failed to lseek", -errno); @@ -278,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; @@ -314,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); @@ -346,7 +391,7 @@ static int delete_xbc(const char *path) ret = fstat(fd, &stat); if (!ret) ret = ftruncate(fd, stat.st_size - - size - 8 - BOOTCONFIG_MAGIC_LEN); + - size - BOOTCONFIG_FOOTER_SIZE); if (ret) ret = -errno; } /* Ignore if there is no boot config in initrd */ @@ -359,7 +404,12 @@ static int delete_xbc(const char *path) static int apply_xbc(const char *path, const char *xbc_path) { - char *buf, *data, *p; + struct { + uint32_t size; + uint32_t csum; + char magic[BOOTCONFIG_MAGIC_LEN]; + } footer; + char *buf, *data; size_t total_size; struct stat stat; const char *msg; @@ -376,10 +426,11 @@ static int apply_xbc(const char *path, const char *xbc_path) csum = xbc_calc_checksum(buf, size); /* Backup the bootconfig data */ - data = calloc(size + BOOTCONFIG_ALIGN + - sizeof(uint32_t) + sizeof(uint32_t) + BOOTCONFIG_MAGIC_LEN, 1); - if (!data) + data = calloc(size + BOOTCONFIG_ALIGN + BOOTCONFIG_FOOTER_SIZE, 1); + if (!data) { + free(buf); return -ENOMEM; + } memcpy(data, buf, size); /* Check the data format */ @@ -425,22 +476,18 @@ static int apply_xbc(const char *path, const char *xbc_path) } /* To align up the total size to BOOTCONFIG_ALIGN, get padding size */ - total_size = stat.st_size + size + sizeof(uint32_t) * 2 + BOOTCONFIG_MAGIC_LEN; + total_size = stat.st_size + size + BOOTCONFIG_FOOTER_SIZE; pad = ((total_size + BOOTCONFIG_ALIGN - 1) & (~BOOTCONFIG_ALIGN_MASK)) - total_size; size += pad; /* Add a footer */ - p = data + size; - *(uint32_t *)p = htole32(size); - p += sizeof(uint32_t); + footer.size = htole32(size); + footer.csum = htole32(csum); + memcpy(footer.magic, BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_LEN); + static_assert(sizeof(footer) == BOOTCONFIG_FOOTER_SIZE); + memcpy(data + size, &footer, BOOTCONFIG_FOOTER_SIZE); - *(uint32_t *)p = htole32(csum); - p += sizeof(uint32_t); - - memcpy(p, BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_LEN); - p += BOOTCONFIG_MAGIC_LEN; - - total_size = p - data; + total_size = size + BOOTCONFIG_FOOTER_SIZE; ret = write(fd, data, total_size); if (ret < total_size) { @@ -478,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; } @@ -487,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; @@ -501,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(); } @@ -524,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); } diff --git a/tools/bootconfig/samples/bad-array-after-comment.bconf b/tools/bootconfig/samples/bad-array-after-comment.bconf new file mode 100644 index 000000000000..fdb6d4e04447 --- /dev/null +++ b/tools/bootconfig/samples/bad-array-after-comment.bconf @@ -0,0 +1,4 @@ +# the first array value must be on the same line as the key +key = # comment + value1, + value2 diff --git a/tools/bootconfig/samples/bad-array-in-next-line.bconf b/tools/bootconfig/samples/bad-array-in-next-line.bconf new file mode 100644 index 000000000000..95a99a3bde8c --- /dev/null +++ b/tools/bootconfig/samples/bad-array-in-next-line.bconf @@ -0,0 +1,4 @@ +# the first array value must be on the same line as the key +key = + value1, + value2 diff --git a/tools/bootconfig/samples/bad-non-closed-brace.bconf b/tools/bootconfig/samples/bad-non-closed-brace.bconf new file mode 100644 index 000000000000..6ed9f3363dde --- /dev/null +++ b/tools/bootconfig/samples/bad-non-closed-brace.bconf @@ -0,0 +1,4 @@ +foo { + bar { + buz + } diff --git a/tools/bootconfig/samples/bad-over-max-brace.bconf b/tools/bootconfig/samples/bad-over-max-brace.bconf new file mode 100644 index 000000000000..74b5dc9e21dc --- /dev/null +++ b/tools/bootconfig/samples/bad-over-max-brace.bconf @@ -0,0 +1,19 @@ +key1 { +key2 { +key3 { +key4 { +key5 { +key6 { +key7 { +key8 { +key9 { +key10 { +key11 { +key12 { +key13 { +key14 { +key15 { +key16 { +key17 { +}}}}}}}}}}}}}}}}} + diff --git a/tools/bootconfig/samples/exp-good-array-space-comment.bconf b/tools/bootconfig/samples/exp-good-array-space-comment.bconf new file mode 100644 index 000000000000..8d3278fa6af5 --- /dev/null +++ b/tools/bootconfig/samples/exp-good-array-space-comment.bconf @@ -0,0 +1 @@ +key = "value1", "value2", "value3"; diff --git a/tools/bootconfig/samples/exp-good-comment-after-value.bconf b/tools/bootconfig/samples/exp-good-comment-after-value.bconf new file mode 100644 index 000000000000..a8e8450db3c0 --- /dev/null +++ b/tools/bootconfig/samples/exp-good-comment-after-value.bconf @@ -0,0 +1 @@ +key = "value"; diff --git a/tools/bootconfig/samples/exp-good-mixed-append.bconf b/tools/bootconfig/samples/exp-good-mixed-append.bconf new file mode 100644 index 000000000000..c2b407901ddd --- /dev/null +++ b/tools/bootconfig/samples/exp-good-mixed-append.bconf @@ -0,0 +1,2 @@ +key = "foo", "bar"; +keyx.subkey = "value"; diff --git a/tools/bootconfig/samples/exp-good-mixed-kv1.bconf b/tools/bootconfig/samples/exp-good-mixed-kv1.bconf new file mode 100644 index 000000000000..8346287d9251 --- /dev/null +++ b/tools/bootconfig/samples/exp-good-mixed-kv1.bconf @@ -0,0 +1,2 @@ +key = "value"; +key.subkey = "another-value"; diff --git a/tools/bootconfig/samples/exp-good-mixed-kv2.bconf b/tools/bootconfig/samples/exp-good-mixed-kv2.bconf new file mode 100644 index 000000000000..40c6232c7cdd --- /dev/null +++ b/tools/bootconfig/samples/exp-good-mixed-kv2.bconf @@ -0,0 +1,2 @@ +key = "another-value"; +key.subkey = "value"; diff --git a/tools/bootconfig/samples/exp-good-mixed-kv3.bconf b/tools/bootconfig/samples/exp-good-mixed-kv3.bconf new file mode 100644 index 000000000000..8368a7bef60a --- /dev/null +++ b/tools/bootconfig/samples/exp-good-mixed-kv3.bconf @@ -0,0 +1,5 @@ +key = "value"; +key { + subkey1; + subkey2 = "foo"; +} diff --git a/tools/bootconfig/samples/exp-good-mixed-override.bconf b/tools/bootconfig/samples/exp-good-mixed-override.bconf new file mode 100644 index 000000000000..58757712ca45 --- /dev/null +++ b/tools/bootconfig/samples/exp-good-mixed-override.bconf @@ -0,0 +1,2 @@ +key = "value2"; +key.foo = "bar"; diff --git a/tools/bootconfig/samples/exp-good-nested-brace.bconf b/tools/bootconfig/samples/exp-good-nested-brace.bconf new file mode 100644 index 000000000000..19e0f51b4553 --- /dev/null +++ b/tools/bootconfig/samples/exp-good-nested-brace.bconf @@ -0,0 +1 @@ +key1.key2.key3.key4.key5.key6.key7.key8.key9.key10.key11.key12.key13.key14.key15.key16; diff --git a/tools/bootconfig/samples/exp-good-override.bconf b/tools/bootconfig/samples/exp-good-override.bconf new file mode 100644 index 000000000000..00bbd30e99ae --- /dev/null +++ b/tools/bootconfig/samples/exp-good-override.bconf @@ -0,0 +1,4 @@ +key { + word = "2", "3"; + new.word = "new"; +} diff --git a/tools/bootconfig/samples/exp-good-printables.bconf b/tools/bootconfig/samples/exp-good-printables.bconf new file mode 100644 index 000000000000..5981d304eacb --- /dev/null +++ b/tools/bootconfig/samples/exp-good-printables.bconf @@ -0,0 +1,2 @@ +key = " + !#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; diff --git a/tools/bootconfig/samples/exp-good-simple.bconf b/tools/bootconfig/samples/exp-good-simple.bconf new file mode 100644 index 000000000000..d17f39421c86 --- /dev/null +++ b/tools/bootconfig/samples/exp-good-simple.bconf @@ -0,0 +1,8 @@ +key { + word1 = "1"; + word2 = "2"; + word3 = "3"; + word4 = "4"; + word5 = "5"; + word6 = "6"; +} diff --git a/tools/bootconfig/samples/exp-good-single.bconf b/tools/bootconfig/samples/exp-good-single.bconf new file mode 100644 index 000000000000..01196910d7f4 --- /dev/null +++ b/tools/bootconfig/samples/exp-good-single.bconf @@ -0,0 +1,3 @@ +key = "1"; +key2 = "2"; +key3 = "alpha", "beta"; diff --git a/tools/bootconfig/samples/exp-good-space-after-value.bconf b/tools/bootconfig/samples/exp-good-space-after-value.bconf new file mode 100644 index 000000000000..a8e8450db3c0 --- /dev/null +++ b/tools/bootconfig/samples/exp-good-space-after-value.bconf @@ -0,0 +1 @@ +key = "value"; diff --git a/tools/bootconfig/samples/exp-good-tree.bconf b/tools/bootconfig/samples/exp-good-tree.bconf new file mode 100644 index 000000000000..b711d38d86fd --- /dev/null +++ b/tools/bootconfig/samples/exp-good-tree.bconf @@ -0,0 +1,8 @@ +key { + word.tree.value = "0"; + word2.tree.value = "1", "2"; +} +other.tree { + value = "2"; + value2 = "3"; +} diff --git a/tools/bootconfig/samples/good-array-space-comment.bconf b/tools/bootconfig/samples/good-array-space-comment.bconf index 45b938dc0695..416fa2ed4109 100644 --- a/tools/bootconfig/samples/good-array-space-comment.bconf +++ b/tools/bootconfig/samples/good-array-space-comment.bconf @@ -1,4 +1,3 @@ -key = # comment - "value1", # comment1 +key = "value1", # comment1 "value2" , # comment2 "value3" diff --git a/tools/bootconfig/samples/good-nested-brace.bconf b/tools/bootconfig/samples/good-nested-brace.bconf new file mode 100644 index 000000000000..980d094f296e --- /dev/null +++ b/tools/bootconfig/samples/good-nested-brace.bconf @@ -0,0 +1,18 @@ +key1 { +key2 { +key3 { +key4 { +key5 { +key6 { +key7 { +key8 { +key9 { +key10 { +key11 { +key12 { +key13 { +key14 { +key15 { +key16 { +}}}}}}}}}}}}}}}} + diff --git a/tools/bootconfig/scripts/ftrace.sh b/tools/bootconfig/scripts/ftrace.sh index 186eed923041..cc5250c64699 100644 --- a/tools/bootconfig/scripts/ftrace.sh +++ b/tools/bootconfig/scripts/ftrace.sh @@ -1,3 +1,4 @@ +#!/bin/sh # SPDX-License-Identifier: GPL-2.0-only clear_trace() { # reset trace output diff --git a/tools/bootconfig/test-bootconfig.sh b/tools/bootconfig/test-bootconfig.sh index a2c484c243f5..fc69f815ce4a 100755 --- a/tools/bootconfig/test-bootconfig.sh +++ b/tools/bootconfig/test-bootconfig.sh @@ -27,16 +27,16 @@ NO=1 xpass() { # pass test command echo "test case $NO ($*)... " - if ! ($@ && echo "\t\t[OK]"); then - echo "\t\t[NG]"; NG=$((NG + 1)) + if ! ($@ && printf "\t\t[OK]\n"); then + printf "\t\t[NG]\n"; NG=$((NG + 1)) fi NO=$((NO + 1)) } xfail() { # fail test command echo "test case $NO ($*)... " - if ! (! $@ && echo "\t\t[OK]"); then - echo "\t\t[NG]"; NG=$((NG + 1)) + if ! (! $@ && printf "\t\t[OK]\n"); then + printf "\t\t[NG]\n"; NG=$((NG + 1)) fi NO=$((NO + 1)) } @@ -48,13 +48,13 @@ echo "Delete command should success without bootconfig" xpass $BOOTCONF -d $INITRD dd if=/dev/zero of=$INITRD bs=4096 count=1 -echo "key = value;" > $TEMPCONF -bconf_size=$(stat -c %s $TEMPCONF) -initrd_size=$(stat -c %s $INITRD) +printf "key = value;" > $TEMPCONF +bconf_size=$(wc -c < $TEMPCONF) +initrd_size=$(wc -c < $INITRD) echo "Apply command test" xpass $BOOTCONF -a $TEMPCONF $INITRD -new_size=$(stat -c %s $INITRD) +new_size=$(wc -c < $INITRD) echo "Show command test" xpass $BOOTCONF $INITRD @@ -69,13 +69,13 @@ echo "Apply command repeat test" xpass $BOOTCONF -a $TEMPCONF $INITRD echo "File size check" -xpass test $new_size -eq $(stat -c %s $INITRD) +xpass test $new_size -eq $(wc -c < $INITRD) echo "Delete command check" xpass $BOOTCONF -d $INITRD echo "File size check" -new_size=$(stat -c %s $INITRD) +new_size=$(wc -c < $INITRD) xpass test $new_size -eq $initrd_size echo "No error messge while applying" @@ -97,19 +97,20 @@ BEGIN { ' > $TEMPCONF xpass $BOOTCONF -a $TEMPCONF $INITRD -echo "badnode" >> $TEMPCONF +printf "badnode\n" >> $TEMPCONF xfail $BOOTCONF -a $TEMPCONF $INITRD echo "Max filesize check" # Max size is 32767 (including terminal byte) -echo -n "data = \"" > $TEMPCONF +printf "data = \"" > $TEMPCONF dd if=/dev/urandom bs=768 count=32 | base64 -w0 >> $TEMPCONF -echo "\"" >> $TEMPCONF +printf "\"\n" >> $TEMPCONF xfail $BOOTCONF -a $TEMPCONF $INITRD -truncate -s 32764 $TEMPCONF -echo "\"" >> $TEMPCONF # add 2 bytes + terminal ('\"\n\0') +dd if=$TEMPCONF of=$OUTFILE bs=1 count=32764 +cp $OUTFILE $TEMPCONF +printf "\"\n" >> $TEMPCONF # add 2 bytes + terminal ('\"\n\0') xpass $BOOTCONF -a $TEMPCONF $INITRD echo "Adding same-key values" @@ -139,7 +140,7 @@ xfail grep -q "baz" $OUTFILE xpass grep -q "qux" $OUTFILE echo "Double/single quotes test" -echo "key = '\"string\"';" > $TEMPCONF +printf "key = '\"string\"';" > $TEMPCONF $BOOTCONF -a $TEMPCONF $INITRD $BOOTCONF $INITRD > $TEMPCONF cat $TEMPCONF @@ -167,8 +168,17 @@ echo > $INITRD xpass $BOOTCONF -a $TEMPCONF $INITRD $BOOTCONF $INITRD > $OUTFILE -xfail grep -q val[[:space:]] $OUTFILE -xpass grep -q val2[[:space:]] $OUTFILE +xfail grep -q 'val[[:space:]]' $OUTFILE +xpass grep -q 'val2[[:space:]]' $OUTFILE + +echo "Showing correct line:column of no closing brace" +cat > $TEMPCONF << EOF +foo { +bar { +} +EOF +$BOOTCONF -a $TEMPCONF $INITRD 2> $OUTFILE +xpass grep -q "1:1" $OUTFILE echo "=== expected failure cases ===" for i in samples/bad-* ; do @@ -178,6 +188,9 @@ done echo "=== expected success cases ===" for i in samples/good-* ; do xpass $BOOTCONF -a $i $INITRD + x="samples/exp-"`basename $i` + $BOOTCONF $i > $TEMPCONF + xpass diff $x $TEMPCONF done |
