grub/grub-core/commands/efi/getenv.c
Matthew Garrett 73746f0367 Fix hex representation of binary variable contents
The getenv code was mishandling the conversion of binary to hex. Grub's
sprintf() doesn't seem to support the full set of format conversions, so
fix this in the nasty way.
2016-01-07 15:31:36 -08:00

153 lines
4.1 KiB
C

/* getenv.c - retrieve EFI variables. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
* Copyright (C) 2014 CoreOS, 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/efi/efi.h>
#include <grub/dl.h>
#include <grub/env.h>
#include <grub/err.h>
#include <grub/extcmd.h>
#include <grub/i18n.h>
#include <grub/misc.h>
#include <grub/mm.h>
GRUB_MOD_LICENSE ("GPLv3+");
static const struct grub_arg_option options_getenv[] = {
{"var-name", 'e', 0,
N_("Environment variable to query"),
N_("VARNAME"), ARG_TYPE_STRING},
{"var-guid", 'g', 0,
N_("GUID of environment variable to query"),
N_("GUID"), ARG_TYPE_STRING},
{"binary", 'b', 0,
N_("Read binary data and represent it as hex"),
0, ARG_TYPE_NONE},
{0, 0, 0, 0, 0, 0}
};
enum options_getenv
{
GETENV_VAR_NAME,
GETENV_VAR_GUID,
GETENV_BINARY,
};
static grub_err_t
grub_cmd_getenv (grub_extcmd_context_t ctxt, int argc, char **args)
{
struct grub_arg_list *state = ctxt->state;
char *envvar = NULL, *guid = NULL, *bindata = NULL, *data = NULL;
grub_size_t datasize;
grub_efi_guid_t efi_var_guid;
grub_efi_boolean_t binary = state[GETENV_BINARY].set;
unsigned int i;
if (!state[GETENV_VAR_NAME].set || !state[GETENV_VAR_GUID].set)
{
grub_error (GRUB_ERR_INVALID_COMMAND, N_("-e and -g are required"));
goto done;
}
if (argc != 1)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unexpected arguments"));
goto done;
}
envvar = state[GETENV_VAR_NAME].arg;
guid = state[GETENV_VAR_GUID].arg;
if (grub_strlen(guid) != 36 ||
guid[8] != '-' ||
guid[13] != '-' ||
guid[18] != '-' ||
guid[23] != '-')
{
grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid GUID"));
goto done;
}
/* Forgive me father for I have sinned */
guid[8] = 0;
efi_var_guid.data1 = grub_strtoul(guid, NULL, 16);
guid[13] = 0;
efi_var_guid.data2 = grub_strtoul(guid + 9, NULL, 16);
guid[18] = 0;
efi_var_guid.data3 = grub_strtoul(guid + 14, NULL, 16);
efi_var_guid.data4[7] = grub_strtoul(guid + 34, NULL, 16);
guid[34] = 0;
efi_var_guid.data4[6] = grub_strtoul(guid + 32, NULL, 16);
guid[32] = 0;
efi_var_guid.data4[5] = grub_strtoul(guid + 30, NULL, 16);
guid[30] = 0;
efi_var_guid.data4[4] = grub_strtoul(guid + 28, NULL, 16);
guid[28] = 0;
efi_var_guid.data4[3] = grub_strtoul(guid + 26, NULL, 16);
guid[26] = 0;
efi_var_guid.data4[2] = grub_strtoul(guid + 24, NULL, 16);
guid[23] = 0;
efi_var_guid.data4[1] = grub_strtoul(guid + 21, NULL, 16);
guid[21] = 0;
efi_var_guid.data4[0] = grub_strtoul(guid + 19, NULL, 16);
data = grub_efi_get_variable(envvar, &efi_var_guid, &datasize);
if (!data || !datasize)
{
grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("No such variable"));
goto done;
}
if (binary)
{
bindata = grub_zalloc(datasize * 2 + 1);
for (i=0; i<datasize; i++)
grub_snprintf(bindata + i*2, 3, "%02x", data[i] & 0xff);
if (grub_env_set (args[0], bindata))
goto done;
}
else if (grub_env_set (args[0], data))
{
goto done;
}
grub_errno = GRUB_ERR_NONE;
done:
grub_free(bindata);
grub_free(data);
return grub_errno;
}
static grub_extcmd_t cmd_getenv;
GRUB_MOD_INIT(getenv)
{
cmd_getenv = grub_register_extcmd ("getenv", grub_cmd_getenv, 0,
N_("-e envvar -g guidenv setvar"),
N_("Read a firmware environment variable"),
options_getenv);
}
GRUB_MOD_FINI(getenv)
{
grub_unregister_extcmd (cmd_getenv);
}