From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 30 Jan 2019 15:08:22 +0100 Subject: [PATCH] blscfg: add support for prepend early initrds to the BLS entries There are cases where is needed one or more initramfs besides the one that is defined in the BLS entry. For example, a user may want to add an early initramfs to override some ACPI tables, load CPU microcode, firmware, etc. Add support to preprend initrds if they are defined as an early_initrd var in grubenv. Also honor GRUB_EARLY_INITRD_LINUX_CUSTOM in /etc/default/grub and use that value to set the early_initrd var when running grub2-mkconfig. Signed-off-by: Javier Martinez Canillas --- grub-core/commands/blscfg.c | 80 +++++++++++++++++++++++++++++++++++++++++++-- util/grub.d/10_linux.in | 3 ++ util/grub.d/10_linux_bls.in | 3 ++ 3 files changed, 84 insertions(+), 2 deletions(-) diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c index aa5bf0d3220..5dcd68b401e 100644 --- a/grub-core/commands/blscfg.c +++ b/grub-core/commands/blscfg.c @@ -660,6 +660,33 @@ static char *expand_val(char *value) return buffer; } +static char **early_initrd_list (const char *initrd) +{ + int nlist = 0; + char **list = NULL; + char *separator; + + while ((separator = grub_strchr (initrd, ' '))) + { + list = grub_realloc (list, (nlist + 2) * sizeof (char *)); + if (!list) + return NULL; + + list[nlist++] = grub_strndup(initrd, separator - initrd); + list[nlist] = NULL; + initrd = separator + 1; + } + + list = grub_realloc (list, (nlist + 2) * sizeof (char *)); + if (!list) + return NULL; + + list[nlist++] = grub_strndup(initrd, grub_strlen(initrd)); + list[nlist] = NULL; + + return list; +} + static void create_entry (struct bls_entry *entry) { int argc = 0; @@ -670,6 +697,9 @@ static void create_entry (struct bls_entry *entry) char *options = NULL; char **initrds = NULL; char *initrd = NULL; + const char *early_initrd = NULL; + char **early_initrds = NULL; + char *initrd_prefix = NULL; char *id = entry->filename; char *dotconf = id; char *hotkey = NULL; @@ -716,13 +746,47 @@ static void create_entry (struct bls_entry *entry) argv[i] = args[i-1]; argv[argc] = NULL; + early_initrd = grub_env_get("early_initrd"); + grub_dprintf ("blscfg", "adding menu entry for \"%s\" with id \"%s\"\n", title, id); - if (initrds) + if (early_initrd) + { + early_initrds = early_initrd_list(early_initrd); + if (!early_initrds) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); + goto finish; + } + + if (initrds != NULL && initrds[0] != NULL) + { + initrd_prefix = grub_strrchr (initrds[0], '/'); + initrd_prefix = grub_strndup(initrds[0], initrd_prefix - initrds[0] + 1); + } + else + { + initrd_prefix = grub_strrchr (clinux, '/'); + initrd_prefix = grub_strndup(clinux, initrd_prefix - clinux + 1); + } + + if (!initrd_prefix) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); + goto finish; + } + } + + if (early_initrds || initrds) { int initrd_size = sizeof ("initrd"); char *tmp; + for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++) + initrd_size += sizeof (" " GRUB_BOOT_DEVICE) \ + + grub_strlen(initrd_prefix) \ + + grub_strlen (early_initrds[i]) + 1; + for (i = 0; initrds != NULL && initrds[i] != NULL; i++) initrd_size += sizeof (" " GRUB_BOOT_DEVICE) \ + grub_strlen (initrds[i]) + 1; @@ -736,12 +800,22 @@ static void create_entry (struct bls_entry *entry) } - tmp = grub_stpcpy(initrd, "initrd "); + tmp = grub_stpcpy(initrd, "initrd"); + for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++) + { + grub_dprintf ("blscfg", "adding early initrd %s\n", early_initrds[i]); + tmp = grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE); + tmp = grub_stpcpy (tmp, initrd_prefix); + tmp = grub_stpcpy (tmp, early_initrds[i]); + grub_free(early_initrds[i]); + } + for (i = 0; initrds != NULL && initrds[i] != NULL; i++) { grub_dprintf ("blscfg", "adding initrd %s\n", initrds[i]); tmp = grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE); tmp = grub_stpcpy (tmp, initrds[i]); + grub_free(initrds[i]); } tmp = grub_stpcpy (tmp, "\n"); } @@ -759,6 +833,8 @@ static void create_entry (struct bls_entry *entry) finish: grub_free (initrd); + grub_free (initrd_prefix); + grub_free (early_initrds); grub_free (initrds); grub_free (options); grub_free (classes); diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in index da2992ac9f1..9c240f92625 100644 --- a/util/grub.d/10_linux.in +++ b/util/grub.d/10_linux.in @@ -167,6 +167,9 @@ EOF if [ "x${GRUB_GRUBENV_UPDATE}" = "xyes" ]; then ${grub_editenv} - set kernelopts="root=${linux_root_device_thisversion} ro ${args}" + if [ -n "${GRUB_EARLY_INITRD_LINUX_CUSTOM}" ]; then + ${grub_editenv} - set early_initrd="${GRUB_EARLY_INITRD_LINUX_CUSTOM}" + fi fi exit 0 diff --git a/util/grub.d/10_linux_bls.in b/util/grub.d/10_linux_bls.in index 175bedd0763..b14951daf82 100644 --- a/util/grub.d/10_linux_bls.in +++ b/util/grub.d/10_linux_bls.in @@ -227,6 +227,9 @@ linux_entry () if [ "x${GRUB_GRUBENV_UPDATE}" = "xyes" ]; then ${grub_editenv} - set kernelopts="root=${linux_root_device_thisversion} ro ${args}" + if [ -n "${GRUB_EARLY_INITRD_LINUX_CUSTOM}" ]; then + ${grub_editenv} - set early_initrd="${GRUB_EARLY_INITRD_LINUX_CUSTOM}" + fi fi exit 0