grub2/0169-Add-efi-export-env-and-efi-load-env-commands.patch
Javier Martinez Canillas 7e98da058f
Cleanup our patchset to reduce the number of patches
This change reorganizes and cleanups our patches to reduce the patch number
from 314 patches to 187. That's achieved by dropping patches that are later
reverted and squashing fixes for earlier patches that introduced features.

There are no code changes and the diff with upstream is the same before and
after the cleanup. Having fewer patches makes easier to manage the patchset
and also will ease to rebase them on top of the latest grub-2.04 release.

Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
2019-07-16 12:30:06 +02:00

361 lines
10 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Wed, 16 Jan 2019 13:21:46 -0500
Subject: [PATCH] Add efi-export-env and efi-load-env commands
This adds "efi-export-env VARIABLE" and "efi-load-env", which manipulate the
environment block stored in the EFI variable
GRUB_ENV-91376aff-cba6-42be-949d-06fde81128e8.
Signed-off-by: Peter Jones <pjones@redhat.com>
---
grub-core/Makefile.core.def | 6 ++
grub-core/commands/efi/env.c | 168 +++++++++++++++++++++++++++++++++++++++++++
grub-core/kern/efi/efi.c | 3 +
grub-core/kern/efi/init.c | 5 --
grub-core/lib/envblk.c | 43 +++++++++++
util/editenv.c | 2 -
util/grub-set-bootflag.c | 1 +
include/grub/efi/efi.h | 5 ++
include/grub/lib/envblk.h | 3 +
9 files changed, 229 insertions(+), 7 deletions(-)
create mode 100644 grub-core/commands/efi/env.c
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index ceb6fc677a0..b662312ca6f 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -776,6 +776,12 @@ module = {
enable = efi;
};
+module = {
+ name = efienv;
+ common = commands/efi/env.c;
+ enable = efi;
+};
+
module = {
name = efifwsetup;
efi = commands/efi/efifwsetup.c;
diff --git a/grub-core/commands/efi/env.c b/grub-core/commands/efi/env.c
new file mode 100644
index 00000000000..a69079786aa
--- /dev/null
+++ b/grub-core/commands/efi/env.c
@@ -0,0 +1,168 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2012 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <grub/dl.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/types.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/efi/api.h>
+#include <grub/efi/efi.h>
+#include <grub/env.h>
+#include <grub/lib/envblk.h>
+#include <grub/command.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const grub_efi_guid_t grub_env_guid = GRUB_EFI_GRUB_VARIABLE_GUID;
+
+static grub_err_t
+grub_efi_export_env(grub_command_t cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ const char *value;
+ char *old_value;
+ struct grub_envblk envblk_s = { NULL, 0 };
+ grub_envblk_t envblk = &envblk_s;
+ grub_err_t err;
+ int changed = 1;
+ grub_efi_status_t status;
+
+ grub_dprintf ("efienv", "argc:%d\n", argc);
+ for (int i = 0; i < argc; i++)
+ grub_dprintf ("efienv", "argv[%d]: %s\n", i, argv[i]);
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("variable name expected"));
+
+ envblk_s.buf = grub_efi_get_variable ("GRUB_ENV", &grub_env_guid,
+ &envblk_s.size);
+ if (!envblk_s.buf || envblk_s.size < 1)
+ {
+ char *buf = grub_malloc (1025);
+ if (!buf)
+ return grub_errno;
+
+ grub_memcpy (buf, GRUB_ENVBLK_SIGNATURE, sizeof (GRUB_ENVBLK_SIGNATURE) - 1);
+ grub_memset (buf + sizeof (GRUB_ENVBLK_SIGNATURE) - 1, '#',
+ DEFAULT_ENVBLK_SIZE - sizeof (GRUB_ENVBLK_SIGNATURE) + 1);
+ buf[1024] = '\0';
+
+ envblk_s.buf = buf;
+ envblk_s.size = 1024;
+ }
+ else
+ {
+ char *buf = grub_realloc (envblk_s.buf, envblk_s.size + 1);
+ if (!buf)
+ return grub_errno;
+
+ envblk_s.buf = buf;
+ envblk_s.buf[envblk_s.size] = '\0';
+ }
+
+ err = grub_envblk_get(envblk, argv[0], &old_value);
+ if (err != GRUB_ERR_NONE)
+ {
+ grub_dprintf ("efienv", "grub_envblk_get returned %d\n", err);
+ return err;
+ }
+
+ value = grub_env_get(argv[0]);
+ if ((!value && !old_value) ||
+ (value && old_value && !grub_strcmp(old_value, value)))
+ changed = 0;
+
+ if (old_value)
+ grub_free(old_value);
+
+ if (changed == 0)
+ {
+ grub_dprintf ("efienv", "No changes necessary\n");
+ return 0;
+ }
+
+ if (value)
+ {
+ grub_dprintf ("efienv", "setting \"%s\" to \"%s\"\n", argv[0], value);
+ grub_envblk_set(envblk, argv[0], value);
+ }
+ else
+ {
+ grub_dprintf ("efienv", "deleting \"%s\" from envblk\n", argv[0]);
+ grub_envblk_delete(envblk, argv[0]);
+ }
+
+ grub_dprintf ("efienv", "envblk is %lu bytes:\n\"%s\"\n", envblk_s.size, envblk_s.buf);
+
+ grub_dprintf ("efienv", "removing GRUB_ENV\n");
+ status = grub_efi_set_variable ("GRUB_ENV", &grub_env_guid, NULL, 0);
+ if (status != GRUB_EFI_SUCCESS)
+ grub_dprintf ("efienv", "removal returned %ld\n", status);
+
+ grub_dprintf ("efienv", "setting GRUB_ENV\n");
+ status = grub_efi_set_variable ("GRUB_ENV", &grub_env_guid,
+ envblk_s.buf, envblk_s.size);
+ if (status != GRUB_EFI_SUCCESS)
+ grub_dprintf ("efienv", "setting GRUB_ENV returned %ld\n", status);
+
+ return 0;
+}
+
+static int
+set_var (const char *name, const char *value,
+ void *whitelist __attribute__((__unused__)))
+{
+ grub_env_set (name, value);
+ return 0;
+}
+
+static grub_err_t
+grub_efi_load_env(grub_command_t cmd __attribute__ ((unused)),
+ int argc, char *argv[] __attribute__((__unused__)))
+{
+ struct grub_envblk envblk_s = { NULL, 0 };
+ grub_envblk_t envblk = &envblk_s;
+
+ envblk_s.buf = grub_efi_get_variable ("GRUB_ENV", &grub_env_guid,
+ &envblk_s.size);
+ if (!envblk_s.buf || envblk_s.size < 1)
+ return 0;
+
+ if (argc > 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unexpected argument"));
+
+ grub_envblk_iterate (envblk, NULL, set_var);
+ grub_free (envblk_s.buf);
+}
+
+static grub_command_t export_cmd, loadenv_cmd;
+
+GRUB_MOD_INIT(lsefi)
+{
+ export_cmd = grub_register_command ("efi-export-env", grub_efi_export_env,
+ N_("VARIABLE_NAME"), N_("Export environment variable to UEFI."));
+ loadenv_cmd = grub_register_command ("efi-load-env", grub_efi_load_env,
+ NULL, N_("Load the grub environment from UEFI."));
+}
+
+GRUB_MOD_FINI(lsefi)
+{
+ grub_unregister_command (export_cmd);
+ grub_unregister_command (loadenv_cmd);
+}
diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
index 4d36fe31177..1079ac74a47 100644
--- a/grub-core/kern/efi/efi.c
+++ b/grub-core/kern/efi/efi.c
@@ -224,6 +224,9 @@ grub_efi_set_variable(const char *var, const grub_efi_guid_t *guid,
if (status == GRUB_EFI_SUCCESS)
return GRUB_ERR_NONE;
+ if (status == GRUB_EFI_NOT_FOUND && datasize == 0)
+ return GRUB_ERR_NONE;
+
return grub_error (GRUB_ERR_IO, "could not set EFI variable `%s'", var);
}
diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c
index e6183a4c44d..d1afa3af11e 100644
--- a/grub-core/kern/efi/init.c
+++ b/grub-core/kern/efi/init.c
@@ -29,11 +29,6 @@
grub_addr_t grub_modbase;
-#define GRUB_EFI_GRUB_VARIABLE_GUID \
- { 0x91376aff, 0xcba6, 0x42be, \
- { 0x94, 0x9d, 0x06, 0xfd, 0xe8, 0x11, 0x28, 0xe8 } \
- }
-
/* Helper for grub_efi_env_init */
static int
set_var (const char *name, const char *value,
diff --git a/grub-core/lib/envblk.c b/grub-core/lib/envblk.c
index 230e0e9d9ab..f89d86d4e8d 100644
--- a/grub-core/lib/envblk.c
+++ b/grub-core/lib/envblk.c
@@ -223,6 +223,49 @@ grub_envblk_delete (grub_envblk_t envblk, const char *name)
}
}
+struct get_var_state {
+ const char * const name;
+ char * value;
+ int found;
+};
+
+static int
+get_var (const char * const name, const char * const value, void *statep)
+{
+ struct get_var_state *state = (struct get_var_state *)statep;
+
+ if (!grub_strcmp(state->name, name))
+ {
+ state->found = 1;
+ state->value = grub_strdup(value);
+ if (!state->value)
+ grub_errno = grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+
+ return 1;
+ }
+
+ return 0;
+}
+
+grub_err_t
+grub_envblk_get (grub_envblk_t envblk, const char * const name, char ** const value)
+{
+ struct get_var_state state = {
+ .name = name,
+ .value = NULL,
+ .found = 0,
+ };
+
+ grub_envblk_iterate(envblk, (void *)&state, get_var);
+
+ *value = state.value;
+
+ if (state.found && !state.value)
+ return grub_errno;
+
+ return GRUB_ERR_NONE;
+}
+
void
grub_envblk_iterate (grub_envblk_t envblk,
void *hook_data,
diff --git a/util/editenv.c b/util/editenv.c
index 41bc7cb1c9a..844a14d90da 100644
--- a/util/editenv.c
+++ b/util/editenv.c
@@ -30,8 +30,6 @@
#include <string.h>
#include <libgen.h>
-#define DEFAULT_ENVBLK_SIZE 1024
-
void
grub_util_create_envblk_file (const char *name)
{
diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c
index bb198f02351..6a79ee67444 100644
--- a/util/grub-set-bootflag.c
+++ b/util/grub-set-bootflag.c
@@ -25,6 +25,7 @@
#include <config-util.h> /* For *_DIR_NAME defines */
#include <grub/types.h>
+#include <grub/err.h>
#include <grub/lib/envblk.h> /* For GRUB_ENVBLK_DEFCFG define */
#include <errno.h>
#include <stdio.h>
diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
index 570a69361a5..2778b95df17 100644
--- a/include/grub/efi/efi.h
+++ b/include/grub/efi/efi.h
@@ -24,6 +24,11 @@
#include <grub/dl.h>
#include <grub/efi/api.h>
+#define GRUB_EFI_GRUB_VARIABLE_GUID \
+ { 0x91376aff, 0xcba6, 0x42be, \
+ { 0x94, 0x9d, 0x06, 0xfd, 0xe8, 0x11, 0x28, 0xe8 } \
+ }
+
/* Variables. */
extern grub_efi_system_table_t *EXPORT_VAR(grub_efi_system_table);
extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle);
diff --git a/include/grub/lib/envblk.h b/include/grub/lib/envblk.h
index c3e65592170..ab969af2461 100644
--- a/include/grub/lib/envblk.h
+++ b/include/grub/lib/envblk.h
@@ -22,6 +22,8 @@
#define GRUB_ENVBLK_SIGNATURE "# GRUB Environment Block\n"
#define GRUB_ENVBLK_DEFCFG "grubenv"
+#define DEFAULT_ENVBLK_SIZE 1024
+
#ifndef ASM_FILE
struct grub_envblk
@@ -33,6 +35,7 @@ typedef struct grub_envblk *grub_envblk_t;
grub_envblk_t grub_envblk_open (char *buf, grub_size_t size);
int grub_envblk_set (grub_envblk_t envblk, const char *name, const char *value);
+grub_err_t grub_envblk_get (grub_envblk_t envblk, const char * const name, char ** const value);
void grub_envblk_delete (grub_envblk_t envblk, const char *name);
void grub_envblk_iterate (grub_envblk_t envblk,
void *hook_data,