diff mbox series

[08/14] discover/grub2: Allow (device)/path references in general script usage

Message ID 20191120024306.16526-9-jk@ozlabs.org
State Accepted
Headers show
Series discover/grub2: Add support for grub2 file specifiers | expand

Commit Message

Jeremy Kerr Nov. 20, 2019, 2:43 a.m. UTC
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 <jk@ozlabs.org>
---
 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 mbox series

Patch

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");
+}