From b22445748f44ed6965f31f45b39abb690d24ec47 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Mon, 11 Nov 2019 19:30:41 +0800 Subject: discover/grub2: Allow (device)/path references in general script usage Currently, we have support for grub2 (device)/path syntax for boot resources. This change allows this syntax for general paths in grub2 scripts (for example, -f tests). This involves exposing grub2_lookup_device, to allow the script execution code to resolve pathnames. Signed-off-by: Jeremy Kerr --- discover/grub2/builtins.c | 50 ++++++++++++++++++++++---- discover/grub2/grub2.c | 4 +-- discover/grub2/grub2.h | 2 ++ test/parser/Makefile.am | 1 + test/parser/test-grub2-devpath-scripting.c | 56 ++++++++++++++++++++++++++++++ 5 files changed, 104 insertions(+), 9 deletions(-) create mode 100644 test/parser/test-grub2-devpath-scripting.c diff --git a/discover/grub2/builtins.c b/discover/grub2/builtins.c index 765c4d7..c726216 100644 --- a/discover/grub2/builtins.c +++ b/discover/grub2/builtins.c @@ -197,6 +197,32 @@ static int builtin_search(struct grub2_script *script, return 0; } +static int parse_to_device_path(struct grub2_script *script, + const char *desc, struct discover_device **devp, + char **pathp) +{ + struct discover_device *dev; + struct grub2_file *file; + + file = grub2_parse_file(script, desc); + if (!file) + return -1; + + dev = script->ctx->device; + if (file->dev) + dev = grub2_lookup_device(script->ctx->handler, file->dev); + + if (!dev) + return -1; + + *devp = dev; + *pathp = talloc_strdup(script, file->path); + + talloc_free(file); + + return 0; +} + /* Note that GRUB does not follow symlinks in evaluating all file * tests but -s, unlike below. However, it seems like a bad idea to * emulate GRUB's behavior (e.g., it would take extra work), so we @@ -204,12 +230,17 @@ static int builtin_search(struct grub2_script *script, static bool builtin_test_op_file(struct grub2_script *script, char op, const char *file) { + struct discover_device *dev; + struct stat statbuf; bool result; + char *path; int rc; - struct stat statbuf; - rc = parser_stat_path(script->ctx, script->ctx->device, - file, &statbuf); + rc = parse_to_device_path(script, file, &dev, &path); + if (rc) + return false; + + rc = parser_stat_path(script->ctx, dev, path, &statbuf); if (rc) return false; @@ -237,16 +268,21 @@ static bool builtin_test_op_file(struct grub2_script *script, char op, static bool builtin_test_op_dir(struct grub2_script *script, char op, const char *dir) { - int rc; + struct discover_device *dev; struct stat statbuf; + char *path; + int rc; if (op != 'd') return false; - rc = parser_stat_path(script->ctx, script->ctx->device, dir, &statbuf); - if (rc) { + rc = parse_to_device_path(script, dir, &dev, &path); + if (rc) + return false; + + rc = parser_stat_path(script->ctx, dev, path, &statbuf); + if (rc) return false; - } return S_ISDIR(statbuf.st_mode); } diff --git a/discover/grub2/grub2.c b/discover/grub2/grub2.c index a08a320..a8d115f 100644 --- a/discover/grub2/grub2.c +++ b/discover/grub2/grub2.c @@ -33,8 +33,8 @@ static const char *const grub2_conf_files[] = { NULL }; -static struct discover_device *grub2_lookup_device( - struct device_handler *handler, const char *desc) +struct discover_device *grub2_lookup_device(struct device_handler *handler, + const char *desc) { struct discover_device *dev; diff --git a/discover/grub2/grub2.h b/discover/grub2/grub2.h index ef32d4b..eabd6d6 100644 --- a/discover/grub2/grub2.h +++ b/discover/grub2/grub2.h @@ -200,6 +200,8 @@ bool resolve_grub2_resource(struct device_handler *handler, /* grub-style device+path parsing */ struct grub2_file *grub2_parse_file(struct grub2_script *script, const char *str); +struct discover_device *grub2_lookup_device(struct device_handler *handler, + const char *desc); /* external parser api */ struct grub2_parser *grub2_parser_create(struct discover_context *ctx); diff --git a/test/parser/Makefile.am b/test/parser/Makefile.am index 0378317..c8e059b 100644 --- a/test/parser/Makefile.am +++ b/test/parser/Makefile.am @@ -33,6 +33,7 @@ parser_TESTS = \ test/parser/test-grub2-search-uuid \ test/parser/test-grub2-search-label \ test/parser/test-grub2-devpath \ + test/parser/test-grub2-devpath-scripting \ test/parser/test-grub2-load-env \ test/parser/test-grub2-save-env \ test/parser/test-grub2-save-env-dash-f \ diff --git a/test/parser/test-grub2-devpath-scripting.c b/test/parser/test-grub2-devpath-scripting.c new file mode 100644 index 0000000..9046ab6 --- /dev/null +++ b/test/parser/test-grub2-devpath-scripting.c @@ -0,0 +1,56 @@ +/* check grub2 device+path string parsing, as used in scripts */ + +#include "parser-test.h" + +#if 0 /* PARSER_EMBEDDED_CONFIG */ + +v= + +# local device, file present +if [ -f "/1-present" ]; then v=${v}a; fi + +# local device, file absent +if [ -f "/1-absent" ]; then v=${v}b; fi; + +# local device by UUID, file present +if [ -f "(00000000-0000-0000-0000-000000000001)/1-present" ]; then v=${v}c; fi; + +# remote device by UUID, file present +if [ -f "(00000000-0000-0000-0000-000000000002)/2-present" ]; then v=${v}d; fi; + +# non-existent device +if [ -f "(00000000-0000-0000-0000-000000000003)/present" ]; then v=${v}e; fi; + +menuentry $v { + linux /vmlinux +} + +#endif + +void run_test(struct parser_test *test) +{ + struct discover_device *dev1, *dev2; + struct discover_boot_option *opt; + struct discover_context *ctx; + + ctx = test->ctx; + + /* set local uuid */ + dev1 = test->ctx->device; + dev1->uuid = "00000000-0000-0000-0000-000000000001"; + + dev2 = test_create_device(test, "extdev"); + dev2->uuid = "00000000-0000-0000-0000-000000000002"; + device_handler_add_device(ctx->handler, dev2); + + test_add_file_data(test, dev1, "/1-present", "x", 1); + test_add_file_data(test, dev2, "/2-present", "x", 1); + + test_read_conf_embedded(test, "/grub/grub.cfg"); + + test_run_parser(test, "grub2"); + + check_boot_option_count(ctx, 1); + opt = get_boot_option(ctx, 0); + check_name(opt, "acd"); +} -- cgit v1.2.1