summaryrefslogtreecommitdiffstats
path: root/discover/grub2/builtins.c
diff options
context:
space:
mode:
Diffstat (limited to 'discover/grub2/builtins.c')
-rw-r--r--discover/grub2/builtins.c208
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[] = {
OpenPOWER on IntegriCloud