grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v2 3/3] grub: add extend variable functionality


From: Prarit Bhargava
Subject: [PATCH v2 3/3] grub: add extend variable functionality
Date: Wed, 16 Jan 2019 13:34:43 -0500

Customers and users of the kernel are commenting that there is no way to update
a grub variable without copy and pasting the existing data.

For example,

[10:57 AM address@hidden grub-2.02]# ./grub-editenv list
saved_entry=0
next_entry=
kernelopts=root=/dev/mapper/rhel_intel--wildcatpass--07-root ro 
crashkernel=auto resume=/dev/mapper/rhel_intel--wildcatpass--07-swap 
rd.lvm.lv=rhel_intel-wildcatpass-07/root 
rd.lvm.lv=rhel_intel-wildcatpass-07/swap console=ttyS0,115200n81  
ignore_loglevel
[10:57 AM address@hidden grub-2.02]# ./grub-editenv - set 
kernelopts="root=/dev/mapper/rhel_intel--wildcatpass--07-root ro 
crashkernel=auto resume=/dev/mapper/rhel_intel--wildcatpass--07-swap 
rd.lvm.lv=rhel_intel-wildcatpass-07/root 
rd.lvm.lv=rhel_intel-wildcatpass-07/swap console=ttyS0,115200n81  
ignore_loglevel newarg"
[10:57 AM address@hidden grub-2.02]# ./grub-editenv list
saved_entry=0
next_entry=
kernelopts=root=/dev/mapper/rhel_intel--wildcatpass--07-root ro 
crashkernel=auto resume=/dev/mapper/rhel_intel--wildcatpass--07-swap 
rd.lvm.lv=rhel_intel-wildcatpass-07/root 
rd.lvm.lv=rhel_intel-wildcatpass-07/swap console=ttyS0,115200n81  
ignore_loglevel newarg

which is cumbersome.

Add functionality to add to an existing variable.  For example,

[10:58 AM address@hidden grub-2.02]# ./grub-editenv list
saved_entry=0
next_entry=
kernelopts=root=/dev/mapper/rhel_intel--wildcatpass--07-root ro 
crashkernel=auto resume=/dev/mapper/rhel_intel--wildcatpass--07-swap 
rd.lvm.lv=rhel_intel-wildcatpass-07/root 
rd.lvm.lv=rhel_intel-wildcatpass-07/swap console=ttyS0,115200n81  
ignore_loglevel
[10:58 AM address@hidden grub-2.02]# ./grub-editenv - set kernelopts+="newarg"
[10:59 AM address@hidden grub-2.02]# ./grub-editenv list
saved_entry=0
next_entry=
kernelopts=root=/dev/mapper/rhel_intel--wildcatpass--07-root ro 
crashkernel=auto resume=/dev/mapper/rhel_intel--wildcatpass--07-swap 
rd.lvm.lv=rhel_intel-wildcatpass-07/root 
rd.lvm.lv=rhel_intel-wildcatpass-07/swap console=ttyS0,115200n81  
ignore_loglevel newarg

Signed-off-by: Prarit Bhargava <address@hidden>
Cc: address@hidden
Cc: address@hidden
Cc: address@hidden
Cc: address@hidden
---
 util/grub-editenv.c | 81 +++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 79 insertions(+), 2 deletions(-)

diff --git a/util/grub-editenv.c b/util/grub-editenv.c
index 5f87b09d924a..bc997c5312d0 100644
--- a/util/grub-editenv.c
+++ b/util/grub-editenv.c
@@ -201,6 +201,49 @@ write_envblk (const char *name, grub_envblk_t envblk)
   fclose (fp);
 }
 
+struct extend_variable_data {
+  grub_envblk_t envblk;
+  const char *name;
+  const char *add;
+};
+
+static int
+extend_variable_hook (const char *varname, const char *value, void *hook_data)
+{
+  char *new = NULL;
+  int ret = GRUB_ERR_NONE;
+  struct extend_variable_data *data = hook_data;
+
+  if (grub_strcmp (data->name, varname))
+    return GRUB_ERR_ITERATE_CONTINUE;
+
+  /* Create the new entry.*/
+  new = grub_zalloc (grub_strlen (value) + grub_strlen (data->add) + 2);
+  if (!new)
+    {
+      return GRUB_ERR_OUT_OF_MEMORY;
+      goto err;
+    }
+  grub_snprintf(new, grub_strlen (value) + grub_strlen (data->add) + 2,
+               "%s %s", value, data->add);
+
+  /* Erase the current entry. */
+  grub_envblk_delete (data->envblk, varname);
+  /* Add the updated entry. */
+  if (! grub_envblk_set (data->envblk, varname, new))
+    {
+      /* Restore the original entry.  This should always work. */
+      grub_envblk_set (data->envblk, varname, value);
+      ret = GRUB_ERR_EOF;
+      goto err;
+    }
+
+ err:
+    grub_free(new);
+    return GRUB_ERR_ITERATE_STOP;
+
+}
+
 static void
 set_variables (const char *name, int argc, char *argv[])
 {
@@ -210,18 +253,52 @@ set_variables (const char *name, int argc, char *argv[])
   while (argc)
     {
       char *p;
+      struct extend_variable_data data;
+      int err;
 
       p = strchr (argv[0], '=');
       if (! p)
         grub_util_error (_("invalid parameter %s"), argv[0]);
 
+      /* Delete "=" to separate variable name and value */
       *(p++) = 0;
 
       if (! grub_strlen(argv[0]))
         grub_util_error (_("No parameter specified"));
 
-      if (! grub_envblk_set (envblk, argv[0], p))
-        grub_util_error ("%s", _("environment block too small"));
+      switch (*(p - 2))
+        {
+          case '+': /* Extend a parameter */
+            *(p - 2) = 0; /* Delete "+" from variable name */
+
+            data.envblk = envblk;
+            data.name = argv[0];
+            data.add = p;
+            err = grub_envblk_iterate (envblk, &data, extend_variable_hook);
+            switch (err)
+              {
+               case GRUB_ERR_ITERATE_STOP: /* Success */
+                  break;
+
+                case GRUB_ERR_OUT_OF_RANGE:
+                case GRUB_ERR_EOF:
+                  grub_util_error ("%s", _("environment block too small"));
+                  break;
+
+                case GRUB_ERR_OUT_OF_MEMORY:
+                  grub_util_error ("%s", _("out of memory"));
+                  break;
+
+                case GRUB_ERR_NONE:
+                  grub_util_error (_("variable %s not found"), argv[0]);
+                 break;
+              }
+            break;
+
+          default: /* Add a new parameter */
+            if (! grub_envblk_set (envblk, argv[0], p))
+              grub_util_error ("%s", _("environment block too small"));
+        }
 
       argc--;
       argv++;
-- 
2.17.2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]