diff options
Diffstat (limited to 'discover/grub2/builtins.c')
-rw-r--r-- | discover/grub2/builtins.c | 208 |
1 files changed, 179 insertions, 29 deletions
diff --git a/discover/grub2/builtins.c b/discover/grub2/builtins.c index 7e92299..ab1407a 100644 --- a/discover/grub2/builtins.c +++ b/discover/grub2/builtins.c @@ -1,4 +1,7 @@ +#define _GNU_SOURCE + +#include <getopt.h> #include <stdio.h> #include <string.h> @@ -43,7 +46,6 @@ static int builtin_linux(struct grub2_script *script, int argc, char *argv[]) { struct discover_boot_option *opt = script->opt; - const char *root; int i; if (!opt) { @@ -58,10 +60,7 @@ static int builtin_linux(struct grub2_script *script, return -1; } - root = script_env_get(script, "root"); - - opt->boot_image = create_grub2_resource(opt, script->ctx->device, - root, argv[1]); + opt->boot_image = create_grub2_resource(script, opt, argv[1]); opt->option->boot_args = NULL; if (argc > 2) @@ -74,8 +73,8 @@ static int builtin_linux(struct grub2_script *script, char* args_sigfile_default = talloc_asprintf(opt, "%s.cmdline.sig", argv[1]); - opt->args_sig_file = create_grub2_resource(opt, script->ctx->device, - root, args_sigfile_default); + opt->args_sig_file = create_grub2_resource(script, opt, + args_sigfile_default); talloc_free(args_sigfile_default); return 0; } @@ -85,7 +84,6 @@ static int builtin_initrd(struct grub2_script *script, int argc, char *argv[]) { struct discover_boot_option *opt = script->opt; - const char *root; if (!opt) { pb_log("grub2 syntax error: 'initrd' statement outside " @@ -99,35 +97,128 @@ static int builtin_initrd(struct grub2_script *script, return -1; } - root = script_env_get(script, "root"); - opt->initrd = create_grub2_resource(opt, script->ctx->device, - root, argv[1]); + opt->initrd = create_grub2_resource(script, opt, argv[1]); return 0; } +static const struct option search_options[] = { + { + .name = "set", + .has_arg = required_argument, + .val = 's', + }, + { + .name = "file", + .has_arg = no_argument, + .val = 'f', + }, + { + .name = "label", + .has_arg = no_argument, + .val = 'l', + }, + { + .name = "fs-uuid", + .has_arg = no_argument, + .val = 'u', + }, + { 0 }, +}; + static int builtin_search(struct grub2_script *script, void *data __attribute__((unused)), int argc, char *argv[]) { - const char *env_var, *spec; - int i; - - env_var = NULL; + const char *env_var, *spec, *res; + struct discover_device *dev; + enum { + LOOKUP_UUID = 'u', + LOOKUP_LABEL = 'l', + LOOKUP_FILE = 'f', + } lookup_type; + + env_var = "root"; + optind = 0; + + /* Default to UUID, for backwards compat with earlier petitboot + * versions. This argument is non-optional in GRUB. */ + lookup_type = LOOKUP_UUID; + + for (;;) { + int c = getopt_long(argc, argv, ":flu", search_options, NULL); + if (c == -1) + break; - for (i = 1; i < argc - 1; i++) { - if (!strncmp(argv[i], "--set=", strlen("--set="))) { - env_var = argv[i] + strlen("--set="); + switch (c) { + case 's': + env_var = optarg; + break; + case LOOKUP_UUID: + case LOOKUP_LABEL: + case LOOKUP_FILE: + lookup_type = c; + break; + case '?': + case ':': break; } } - if (!env_var) + if (!strlen(env_var)) return 0; - spec = argv[argc - 1]; + if (optind >= argc) + return -1; + + spec = argv[optind]; + res = NULL; + + switch (lookup_type) { + case LOOKUP_UUID: + dev = device_lookup_by_uuid(script->ctx->handler, + spec); + res = dev ? dev->device->id : spec; + break; + case LOOKUP_LABEL: + dev = device_lookup_by_label(script->ctx->handler, + spec); + if (dev) + res = dev->device->id; + break; + case LOOKUP_FILE: + /* not yet implemented */ + break; + } + + if (res) + script_env_set(script, env_var, res); + + 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); - script_env_set(script, env_var, spec); + talloc_free(file); return 0; } @@ -139,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; @@ -172,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); } @@ -300,6 +401,51 @@ static int builtin_test(struct grub2_script *script, return rc ? 0 : 1; } +static int builtin_source(struct grub2_script *script, + void *data __attribute__((unused)), + int argc, char *argv[]) +{ + struct grub2_statements *statements; + struct discover_device *dev; + const char *filename; + char *path, *buf; + int rc, len; + + if (argc != 2) + return false; + + /* limit script recursion */ + if (script->include_depth >= 10) + return false; + + rc = parse_to_device_path(script, argv[1], &dev, &path); + if (rc) + return false; + + rc = parser_request_file(script->ctx, dev, path, &buf, &len); + if (rc) + return false; + + /* save current script state */ + statements = script->statements; + filename = script->filename; + script->include_depth++; + + rc = grub2_parser_parse(script->parser, argv[1], buf, len); + + if (!rc) + statements_execute(script, script->statements); + + talloc_free(script->statements); + + /* restore state */ + script->statements = statements; + script->filename = filename; + script->include_depth--; + + return !rc; +} + static int builtin_true(struct grub2_script *script __attribute__((unused)), void *data __attribute__((unused)), int argc __attribute__((unused)), @@ -390,7 +536,11 @@ static struct { { .name = "blscfg", .fn = builtin_blscfg, - } + }, + { + .name = "source", + .fn = builtin_source, + }, }; static const char *nops[] = { |