[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