273 lines
6.4 KiB
Diff
273 lines
6.4 KiB
Diff
From 3cf4fdf8d17423dea4e5913ab14fb6305f3c2571 Mon Sep 17 00:00:00 2001
|
|
From: Michael Chang <mchang@suse.com>
|
|
Date: Fri, 18 Feb 2022 21:43:38 +0800
|
|
Subject: [PATCH 4/5] Introduce prep_load_env command
|
|
|
|
This command will accept grub disk device and perform load_env for
|
|
environment block located at end of PReP partition which belongs to that
|
|
input disk device. All variables read from that environment block are
|
|
exported to grub as environment variables.
|
|
|
|
Please note there's no support for whitelist variables and also
|
|
--skip-sig option compared to ordinary load_env command.
|
|
|
|
v2:
|
|
To avoid disrupting the boot process with errors, it's important to log
|
|
any errors that may occur and always return GRUB_ERR_NONE.
|
|
|
|
v3:
|
|
Making the new module powerpc_ieee1275 specific.
|
|
|
|
Signed-off-by: Michael Chang <mchang@suse.com>
|
|
---
|
|
grub-core/Makefile.core.def | 5 +
|
|
grub-core/commands/prep_loadenv.c | 227 ++++++++++++++++++++++++++++++
|
|
2 files changed, 232 insertions(+)
|
|
create mode 100644 grub-core/commands/prep_loadenv.c
|
|
|
|
--- a/grub-core/Makefile.core.def
|
|
+++ b/grub-core/Makefile.core.def
|
|
@@ -2673,3 +2673,9 @@
|
|
common = lib/libtasn1_wrap/tests/Test_strings.c;
|
|
common = lib/libtasn1_wrap/wrap_tests.c;
|
|
};
|
|
+
|
|
+module = {
|
|
+ name = prep_loadenv;
|
|
+ common = commands/prep_loadenv.c;
|
|
+ enable = powerpc_ieee1275;
|
|
+};
|
|
--- /dev/null
|
|
+++ b/grub-core/commands/prep_loadenv.c
|
|
@@ -0,0 +1,230 @@
|
|
+#include <grub/dl.h>
|
|
+#include <grub/mm.h>
|
|
+#include <grub/file.h>
|
|
+#include <grub/disk.h>
|
|
+#include <grub/misc.h>
|
|
+#include <grub/err.h>
|
|
+#include <grub/env.h>
|
|
+#include <grub/partition.h>
|
|
+#include <grub/lib/envblk.h>
|
|
+#include <grub/extcmd.h>
|
|
+#include <grub/i18n.h>
|
|
+#include <grub/gpt_partition.h>
|
|
+
|
|
+GRUB_MOD_LICENSE ("GPLv3+");
|
|
+
|
|
+static char *
|
|
+match_substr (regmatch_t *match, const char *str)
|
|
+{
|
|
+ if (match->rm_so != -1)
|
|
+ {
|
|
+ char *substr;
|
|
+ regoff_t sz = match->rm_eo - match->rm_so;
|
|
+
|
|
+ if (!sz)
|
|
+ return NULL;
|
|
+ substr = grub_malloc (1 + sz);
|
|
+ if (!substr)
|
|
+ {
|
|
+ grub_print_error ();
|
|
+ return NULL;
|
|
+ }
|
|
+ grub_memcpy (substr, str + match->rm_so, sz);
|
|
+ substr[sz] = '\0';
|
|
+ return substr;
|
|
+ }
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static int
|
|
+is_prep_partition (grub_device_t dev)
|
|
+{
|
|
+ if (!dev->disk)
|
|
+ return 0;
|
|
+ if (!dev->disk->partition)
|
|
+ return 0;
|
|
+ if (grub_strcmp (dev->disk->partition->partmap->name, "msdos") == 0)
|
|
+ return (dev->disk->partition->msdostype == 0x41);
|
|
+
|
|
+ if (grub_strcmp (dev->disk->partition->partmap->name, "gpt") == 0)
|
|
+ {
|
|
+ struct grub_gpt_partentry gptdata;
|
|
+ grub_partition_t p = dev->disk->partition;
|
|
+ int ret = 0;
|
|
+ dev->disk->partition = dev->disk->partition->parent;
|
|
+
|
|
+ if (grub_disk_read (dev->disk, p->offset, p->index,
|
|
+ sizeof (gptdata), &gptdata) == 0)
|
|
+ {
|
|
+ const grub_guid_t template = {
|
|
+ grub_cpu_to_le32_compile_time (0x9e1a2d38),
|
|
+ grub_cpu_to_le16_compile_time (0xc612),
|
|
+ grub_cpu_to_le16_compile_time (0x4316),
|
|
+ { 0xaa, 0x26, 0x8b, 0x49, 0x52, 0x1e, 0x5a, 0x8b }
|
|
+ };
|
|
+
|
|
+ ret = grub_memcmp (&template, &gptdata.type,
|
|
+ sizeof (template)) == 0;
|
|
+ }
|
|
+ dev->disk->partition = p;
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+part_hook (grub_disk_t disk, const grub_partition_t partition, void *data)
|
|
+{
|
|
+ char **ret = data;
|
|
+ char *partition_name, *devname;
|
|
+ grub_device_t dev;
|
|
+
|
|
+ partition_name = grub_partition_get_name (partition);
|
|
+ if (! partition_name)
|
|
+ return 2;
|
|
+
|
|
+ devname = grub_xasprintf ("%s,%s", disk->name, partition_name);
|
|
+ grub_free (partition_name);
|
|
+ if (!devname)
|
|
+ return 2;
|
|
+
|
|
+ dev = grub_device_open (devname);
|
|
+ if (!dev)
|
|
+ {
|
|
+ grub_free (devname);
|
|
+ return 2;
|
|
+ }
|
|
+ if (is_prep_partition (dev))
|
|
+ {
|
|
+ *ret = devname;
|
|
+ return 1;
|
|
+ }
|
|
+ grub_free (devname);
|
|
+ grub_device_close (dev);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+set_var (const char *name, const char *value,
|
|
+ void *hook_data __attribute__ ((unused)))
|
|
+{
|
|
+ grub_env_set (name, value);
|
|
+ grub_env_export (name);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static grub_err_t
|
|
+prep_read_envblk (const char *devname)
|
|
+{
|
|
+ char *buf = NULL;
|
|
+ grub_device_t dev = NULL;
|
|
+ grub_envblk_t envblk = NULL;
|
|
+
|
|
+ dev = grub_device_open (devname);
|
|
+ if (!dev)
|
|
+ return grub_errno;
|
|
+
|
|
+ if (!dev->disk || !dev->disk->partition)
|
|
+ {
|
|
+ grub_error (GRUB_ERR_BAD_DEVICE, "disk device required");
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ buf = grub_malloc (GRUB_ENVBLK_PREP_SIZE);
|
|
+ if (!buf)
|
|
+ goto fail;
|
|
+
|
|
+ if (grub_disk_read (dev->disk, dev->disk->partition->len - (GRUB_ENVBLK_PREP_SIZE >> GRUB_DISK_SECTOR_BITS), 0, GRUB_ENVBLK_PREP_SIZE, buf))
|
|
+ goto fail;
|
|
+
|
|
+ envblk = grub_envblk_open (buf, GRUB_ENVBLK_PREP_SIZE);
|
|
+ if (!envblk)
|
|
+ {
|
|
+ grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid environment block");
|
|
+ goto fail;
|
|
+ }
|
|
+ grub_envblk_iterate (envblk, NULL, set_var);
|
|
+
|
|
+ fail:
|
|
+ if (envblk)
|
|
+ grub_envblk_close (envblk);
|
|
+ else
|
|
+ grub_free (buf);
|
|
+ if (dev)
|
|
+ grub_device_close (dev);
|
|
+ return grub_errno;
|
|
+}
|
|
+
|
|
+static grub_err_t
|
|
+prep_partname (const char *devname, char **prep)
|
|
+{
|
|
+ grub_device_t dev = NULL;
|
|
+ grub_err_t err;
|
|
+ int ret;
|
|
+
|
|
+ dev = grub_device_open (devname);
|
|
+ if (!dev)
|
|
+ return grub_errno;
|
|
+
|
|
+ ret = grub_partition_iterate (dev->disk, part_hook, prep);
|
|
+ if (ret == 1 && *prep)
|
|
+ {
|
|
+ err = GRUB_ERR_NONE;
|
|
+ goto out;
|
|
+ }
|
|
+ else if (ret == 0 && grub_errno == GRUB_ERR_NONE)
|
|
+ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, "no prep partition");
|
|
+ else
|
|
+ err = grub_errno;
|
|
+
|
|
+ out:
|
|
+ grub_device_close (dev);
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static grub_err_t
|
|
+grub_cmd_prep_loadenv (grub_command_t cmd __attribute__ ((unused)),
|
|
+ int argc,
|
|
+ char **argv)
|
|
+{
|
|
+ char *devname, *prep = NULL;
|
|
+ grub_err_t err;
|
|
+
|
|
+ if (argc < 1)
|
|
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
|
|
+
|
|
+ devname = grub_file_get_device_name(argv[0]);
|
|
+ if (!devname)
|
|
+ return grub_errno;
|
|
+
|
|
+ err = prep_partname (devname, &prep);
|
|
+ if (prep == NULL || err != GRUB_ERR_NONE)
|
|
+ goto out;
|
|
+
|
|
+ err = prep_read_envblk (prep);
|
|
+
|
|
+ out:
|
|
+ grub_free (devname);
|
|
+ grub_free (prep);
|
|
+
|
|
+ if (err)
|
|
+ grub_print_error ();
|
|
+ return GRUB_ERR_NONE;
|
|
+}
|
|
+
|
|
+static grub_command_t cmd_prep_load;
|
|
+
|
|
+GRUB_MOD_INIT(prep_loadenv)
|
|
+{
|
|
+ cmd_prep_load =
|
|
+ grub_register_command("prep_load_env", grub_cmd_prep_loadenv,
|
|
+ "DEVICE",
|
|
+ N_("Load variables from environment block file."));
|
|
+}
|
|
+
|
|
+GRUB_MOD_FINI(prep_loadenv)
|
|
+{
|
|
+ grub_unregister_command (cmd_prep_load);
|
|
+}
|