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