Skip to content

Commit

Permalink
discover/grub2: Allow (device)/path references in general script usage
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
jk-ozlabs committed Nov 29, 2019
1 parent 9fc2ac6 commit b224457
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 9 deletions.
50 changes: 43 additions & 7 deletions discover/grub2/builtins.c
Expand Up @@ -197,19 +197,50 @@ 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
* implement the behavior that coreutils' test binary has. */
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;

Expand Down Expand Up @@ -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);
}
Expand Down
4 changes: 2 additions & 2 deletions discover/grub2/grub2.c
Expand Up @@ -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;

Expand Down
2 changes: 2 additions & 0 deletions discover/grub2/grub2.h
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions test/parser/Makefile.am
Expand Up @@ -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 \
Expand Down
56 changes: 56 additions & 0 deletions 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");
}

0 comments on commit b224457

Please sign in to comment.