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 root@intel-wildcatpass-07 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 root@intel-wildcatpass-07 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 root@intel-wildcatpass-07 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 root@intel-wildcatpass-07 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 root@intel-wildcatpass-07 grub-2.02]# ./grub-editenv - set kernelopts+="newarg" [10:59 AM root@intel-wildcatpass-07 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 <pra...@redhat.com> Cc: mleit...@redhat.com Cc: pjo...@redhat.com Cc: javi...@redhat.com Cc: ar...@redhat.com --- 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 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel