discover/grub2: Implement load_env
authorJeremy Kerr <jk@ozlabs.org>
Fri, 27 Sep 2013 06:21:53 +0000 (14:21 +0800)
committerJeremy Kerr <jk@ozlabs.org>
Tue, 1 Oct 2013 05:49:14 +0000 (13:49 +0800)
Use the new parser_request_file API to access the GRUB environment
block.

Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
discover/grub2/Makefile.am
discover/grub2/builtins.c
discover/grub2/env.c [new file with mode: 0644]
test/parser/Makefile.am
test/parser/test-grub2-load-env.c [new file with mode: 0644]

index 71f328243b25f7fc6c01da07b1b07d31ec6bf883..902f94f331400d65fefbad964c587e37186d9b87 100644 (file)
@@ -30,6 +30,7 @@ grub2-parser.ro$(EXEEXT): $(grub2_parser_ro_OBJECTS)
 
 grub2_parser_ro_SOURCES = \
        builtins.c \
+       env.c \
        grub2.h \
        grub2.c \
        lexer.l \
index 7a5d8672a6a89285bfe268732dbb57ec04892d25..71ae61a3ae97118ed63e7f30303e2c4d4c09dd7c 100644 (file)
@@ -256,6 +256,10 @@ static int builtin_nop(struct grub2_script *script __attribute__((unused)),
        return 0;
 }
 
+extern int builtin_load_env(struct grub2_script *script,
+               void *data __attribute__((unused)),
+               int argc, char *argv[]);
+
 static struct {
        const char *name;
        grub2_function fn;
@@ -296,6 +300,10 @@ static struct {
                .name = "false",
                .fn = builtin_false,
        },
+       {
+               .name = "load_env",
+               .fn = builtin_load_env,
+       },
 };
 
 static const char *nops[] = {
diff --git a/discover/grub2/env.c b/discover/grub2/env.c
new file mode 100644 (file)
index 0000000..e28c9fe
--- /dev/null
@@ -0,0 +1,107 @@
+
+#include <stdio.h>
+#include <string.h>
+
+#include <log/log.h>
+#include <types/types.h>
+#include <talloc/talloc.h>
+#include <array-size/array-size.h>
+
+#include <discover/parser.h>
+#include <discover/file.h>
+
+#include "grub2.h"
+
+static const char *default_envfile = "grubenv";
+static const char *signature = "# GRUB Environment Block\n";
+
+static int parse_buf_to_env(struct grub2_script *script, void *buf, int len)
+{
+       char *tmp, *line, *sep;
+       int siglen;
+
+       siglen = strlen(signature);
+
+       if (len < siglen) {
+               pb_log("grub environment block too small\n");
+               return -1;
+       }
+
+       if (memcmp(buf, signature, siglen)) {
+               pb_log("grub environment block has invalid signature\n");
+               return -1;
+       }
+
+       buf += siglen;
+
+       for (line = strtok_r(buf, "\n", &tmp); line;
+                               line = strtok_r(NULL, "\n", &tmp)) {
+
+               if (*line == '#')
+                       continue;
+
+               sep = strchr(line, '=');
+               if (!sep)
+                       continue;
+               if (sep == line)
+                       continue;
+
+               *sep = '\0';
+               script_env_set(script, line, sep + 1);
+       }
+
+       return 0;
+}
+
+int builtin_load_env(struct grub2_script *script,
+               void *data __attribute__((unused)),
+               int argc, char *argv[]);
+
+int builtin_load_env(struct grub2_script *script,
+               void *data __attribute__((unused)),
+               int argc, char *argv[])
+{
+       struct discover_device *dev = script->ctx->device;
+       const char *envfile;
+       char *buf, *envpath;
+       int rc, len;
+
+       /* we only support local filesystems */
+       if (!dev->mounted) {
+               pb_log("load_env: can't load from a non-mounted device (%s)\n",
+                               dev->device->id);
+               return -1;
+       }
+
+       if (argc == 3 && !strcmp(argv[1], "-f"))
+               envfile = argv[2];
+       else
+               envfile = default_envfile;
+
+       envpath = talloc_asprintf(script, "%s/%s",
+                               script_env_get(script, "prefix") ? : "",
+                               envfile);
+
+       rc = parser_request_file(script->ctx, dev, envpath, &buf, &len);
+
+       if (!rc)
+               rc = parse_buf_to_env(script, buf, len);
+
+       talloc_free(buf);
+
+       return 0;
+}
+
+int builtin_save_env(struct grub2_script *script,
+               void *data __attribute__((unused)),
+               int argc, char *argv[]);
+
+int builtin_save_env(struct grub2_script *script __attribute__((unused)),
+               void *data __attribute__((unused)),
+               int argc __attribute__((unused)),
+               char *argv[] __attribute__((unused)))
+{
+       /* todo: save */
+       return 0;
+}
+
index e7146c5545ec43be0883867cacadba912f431146..165b9ae3c37e30420ddeca718af127ac4be32882 100644 (file)
@@ -33,6 +33,7 @@ TESTS = \
        test-grub2-default-multiword \
        test-grub2-multiple-resolve \
        test-grub2-single-line-if \
+       test-grub2-load-env \
        test-grub2-f18-ppc64 \
        test-grub2-ubuntu-13_04-x86 \
        test-grub2-lexer-error \
diff --git a/test/parser/test-grub2-load-env.c b/test/parser/test-grub2-load-env.c
new file mode 100644 (file)
index 0000000..2f4e96e
--- /dev/null
@@ -0,0 +1,32 @@
+
+#include "parser-test.h"
+
+#if 0 /* PARSER_EMBEDDED_CONFIG */
+load_env
+menuentry 'Linux' {
+       linux   $kernel
+}
+#endif
+
+void run_test(struct parser_test *test)
+{
+       struct discover_boot_option *opt;
+       struct discover_context *ctx;
+
+       test_add_file_string(test, test->ctx->device,
+                               "/boot/grub/grubenv",
+                               "# GRUB Environment Block\n"
+                               "kernel=vmlinux-from-env\n");
+
+       test_read_conf_embedded(test);
+       test_run_parser(test, "grub2");
+
+       ctx = test->ctx;
+
+       check_boot_option_count(ctx, 1);
+       opt = get_boot_option(ctx, 0);
+
+       check_name(opt, "Linux");
+       check_resolved_local_resource(opt->boot_image, ctx->device,
+                       "/vmlinux-from-env");
+}