[PATCH 0/7] efi: Improvements to env print -e

From: Simon Glass <sjg@chromium.org> Printing EFI variables can be quite verbose, with many hundreds of lines of text. Part of this is because GUIDs and hex dumps are included. It can also be hard to find a few variables visually in an unsorted list. This series makes the feature more user-friendly: - Puts verbose output behind a -v flag, so that 'env print -e' behaves more like 'env print' - Adds a -s option to sort the list Simon Glass (7): efi: Move guid used for variables to common files efi: Enable access to efi variables from the app efi: Change env print -e to show only names by default efi: Rename var_name64 to name in efi_dump_var_all() efi: Refactor error handling in efi_dump_var_all() efi: nvedit: Place variables in an alist before printing them cmd: Add -s flag to printenv -e for sorted output cmd/Kconfig | 1 + cmd/nvedit.c | 6 +- cmd/nvedit_efi.c | 164 ++++++++++++------ doc/usage/cmd/env.rst | 9 +- doc/usage/cmd/printenv.rst | 84 ++++++++- include/efi.h | 2 + include/efi_loader.h | 1 - lib/efi/device_path.c | 3 + lib/efi_loader/efi_var_common.c | 3 - .../py/tests/test_efi_secboot/test_authvar.py | 46 ++--- 10 files changed, 231 insertions(+), 88 deletions(-) -- 2.43.0 base-commit: 96d39714e407ff11177434b835ab1a7d46c8c695 branch: loadt

From: Simon Glass <sjg@chromium.org> Move efi_guid_image_security_database to a common file so that it can be used by the app. Signed-off-by: Simon Glass <sjg@chromium.org> --- include/efi.h | 2 ++ include/efi_loader.h | 1 - lib/efi/device_path.c | 3 +++ lib/efi_loader/efi_var_common.c | 3 --- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/efi.h b/include/efi.h index 5e15a87ed3b..3558c03db23 100644 --- a/include/efi.h +++ b/include/efi.h @@ -157,6 +157,8 @@ extern const efi_guid_t efi_guid_fdt; /* GUID of the EFI_DRIVER_BINDING_PROTOCOL */ extern const efi_guid_t efi_guid_driver_binding_protocol; extern const efi_guid_t efi_guid_component_name2; +/* GUIDs for authentication - most of these are still in efi_loader.h */ +extern const efi_guid_t efi_guid_image_security_database; /* Generic EFI table header */ struct efi_table_hdr { diff --git a/include/efi_loader.h b/include/efi_loader.h index a475ebb5413..52314c33533 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -353,7 +353,6 @@ extern const efi_guid_t efi_guid_hii_config_access_protocol; extern const efi_guid_t efi_guid_hii_database_protocol; extern const efi_guid_t efi_guid_hii_string_protocol; /* GUIDs for authentication */ -extern const efi_guid_t efi_guid_image_security_database; extern const efi_guid_t efi_guid_sha256; extern const efi_guid_t efi_guid_cert_x509; extern const efi_guid_t efi_guid_cert_x509_sha256; diff --git a/lib/efi/device_path.c b/lib/efi/device_path.c index 449b9d4239b..1dc28f81146 100644 --- a/lib/efi/device_path.c +++ b/lib/efi/device_path.c @@ -39,6 +39,9 @@ const efi_guid_t efi_guid_driver_binding_protocol = EFI_DRIVER_BINDING_PROTOCOL_GUID; const efi_guid_t efi_guid_component_name2 = EFI_COMPONENT_NAME2_PROTOCOL_GUID; +const efi_guid_t efi_guid_image_security_database = + EFI_IMAGE_SECURITY_DATABASE_GUID; + /* template EFI_DP_END node: */ const struct efi_device_path EFI_DP_END = { .type = DEVICE_PATH_TYPE_END, diff --git a/lib/efi_loader/efi_var_common.c b/lib/efi_loader/efi_var_common.c index 4b34a58b4cf..f2fbf67f5ed 100644 --- a/lib/efi_loader/efi_var_common.c +++ b/lib/efi_loader/efi_var_common.c @@ -25,9 +25,6 @@ struct efi_auth_var_name_type { const enum efi_auth_var_type type; }; -const efi_guid_t efi_guid_image_security_database = - EFI_IMAGE_SECURITY_DATABASE_GUID; - static const struct efi_auth_var_name_type name_type[] = { {u"PK", &efi_global_variable_guid, EFI_AUTH_VAR_PK}, {u"KEK", &efi_global_variable_guid, EFI_AUTH_VAR_KEK}, -- 2.43.0

From: Simon Glass <sjg@chromium.org> Enable the 'setenv -e' feature. Signed-off-by: Simon Glass <sjg@chromium.org> --- cmd/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/Kconfig b/cmd/Kconfig index fe9fb11ff95..882a4ee02e3 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -676,6 +676,7 @@ config CMD_ENV_FLAGS config CMD_NVEDIT_EFI bool "env [set|print] -e - set/print UEFI variables" depends on EFI_LOADER || EFI_APP + default y if EFI_APP imply HEXDUMP help UEFI variables are encoded as some form of U-Boot variables. -- 2.43.0

From: Simon Glass <sjg@chromium.org> Change the default behavior of 'printenv -e' to show only EFI variable names. The previous verbose output is now available with the -v flag. This makes the command more user-friendly for quick variable listing. Update documentation to reflect the new behavior and provide examples of all three output modes: default (names only), -n (details without hex dump), and -v (full verbose output). It might be nicer to use -d to enable the dump, rather than have it on by default. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <sjg@chromium.org> --- cmd/nvedit.c | 5 +- cmd/nvedit_efi.c | 65 +++++++++++-------- doc/usage/cmd/env.rst | 7 +- doc/usage/cmd/printenv.rst | 20 ++++-- .../py/tests/test_efi_secboot/test_authvar.py | 46 ++++++------- 5 files changed, 84 insertions(+), 59 deletions(-) diff --git a/cmd/nvedit.c b/cmd/nvedit.c index 1f259801293..8dbe8a03fd5 100644 --- a/cmd/nvedit.c +++ b/cmd/nvedit.c @@ -1174,7 +1174,7 @@ U_BOOT_LONGHELP(env, #endif "env print [-a | name ...] - print environment\n" #if defined(CONFIG_CMD_NVEDIT_EFI) - "env print -e [-guid guid] [-n] [name ...] - print UEFI environment\n" + "env print -e [-guid guid] [-n] [-v] [name ...] print UEFI environment\n" #endif #if defined(CONFIG_CMD_RUN) "env run var [...] - run commands in an environment variable\n" @@ -1221,10 +1221,11 @@ U_BOOT_CMD_COMPLETE( "print environment variables", "[-a]\n - print [all] values of all environment variables\n" #if defined(CONFIG_CMD_NVEDIT_EFI) - "printenv -e [-guid guid][-n] [name ...]\n" + "printenv -e [-guid guid][-n] [-v] [name ...]\n" " - print UEFI variable 'name' or all the variables\n" " \"-guid\": GUID xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\n" " \"-n\": suppress dumping variable's value\n" + " \"-v\": show GUID, flags, size; also dump (without -n)\n" #endif "printenv name ...\n" " - print value of environment variable 'name'", diff --git a/cmd/nvedit_efi.c b/cmd/nvedit_efi.c index 32b7d049074..12c98a5d5c4 100644 --- a/cmd/nvedit_efi.c +++ b/cmd/nvedit_efi.c @@ -43,11 +43,13 @@ static const struct { * * @name: Name of the variable * @guid: Vendor GUID - * @verbose: if true, dump data + * @verbose: if true, show detailed information + * @nodump: if true, don't show hexadecimal dump * * Show information encoded in one UEFI variable */ -static void efi_dump_single_var(u16 *name, const efi_guid_t *guid, bool verbose) +static void efi_dump_single_var(u16 *name, const efi_guid_t *guid, + bool verbose, bool nodump) { u32 attributes; u8 *data; @@ -75,23 +77,27 @@ static void efi_dump_single_var(u16 *name, const efi_guid_t *guid, bool verbose) if (ret != EFI_SUCCESS) goto out; - rtc_to_tm(time, &tm); - printf("%ls:\n %pUl (%pUs)\n", name, guid, guid); - if (attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) - printf(" %04d-%02d-%02d %02d:%02d:%02d\n", tm.tm_year, - tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); - printf(" "); - for (count = 0, i = 0; i < ARRAY_SIZE(efi_var_attrs); i++) - if (attributes & efi_var_attrs[i].mask) { - if (count) - putc('|'); - count++; - puts(efi_var_attrs[i].text); - } - printf(", DataSize = 0x%zx\n", size); - if (verbose) - print_hex_dump(" ", DUMP_PREFIX_OFFSET, 16, 1, - data, size, true); + if (verbose) { + rtc_to_tm(time, &tm); + printf("%ls:\n %pUl (%pUs)\n", name, guid, guid); + if (attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) + printf(" %04d-%02d-%02d %02d:%02d:%02d\n", tm.tm_year, + tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + printf(" "); + for (count = 0, i = 0; i < ARRAY_SIZE(efi_var_attrs); i++) + if (attributes & efi_var_attrs[i].mask) { + if (count) + putc('|'); + count++; + puts(efi_var_attrs[i].text); + } + printf(", DataSize = 0x%zx\n", size); + if (!nodump) + print_hex_dump(" ", DUMP_PREFIX_OFFSET, 16, 1, + data, size, true); + } else { + printf("%ls\n", name); + } out: free(data); @@ -130,13 +136,15 @@ out: * * @argc: Number of arguments (variables) * @argv: Argument (variable name) array - * @verbose: if true, dump data + * @guid_p: GUID to filter by, or NULL for all + * @verbose: if true, show detailed information + * @nodump: if true, don't show hexadecimal dump * Return: CMD_RET_SUCCESS on success, or CMD_RET_RET_FAILURE * * Show information encoded in all the UEFI variables */ static int efi_dump_var_all(int argc, char *const argv[], - const efi_guid_t *guid_p, bool verbose) + const efi_guid_t *guid_p, bool verbose, bool nodump) { u16 *var_name16, *p; efi_uintn_t buf_size, size; @@ -176,7 +184,7 @@ static int efi_dump_var_all(int argc, char *const argv[], continue; if (!argc || match_name(argc, argv, var_name16)) { match = true; - efi_dump_single_var(var_name16, &guid, verbose); + efi_dump_single_var(var_name16, &guid, verbose, nodump); } } free(var_name16); @@ -199,16 +207,18 @@ static int efi_dump_var_all(int argc, char *const argv[], * Return: CMD_RET_SUCCESS on success, or CMD_RET_RET_FAILURE * * This function is for "env print -e" or "printenv -e" command: - * => env print -e [-n] [-guid <guid> | -all] [var [...]] + * => env print -e [-v] [-guid <guid> | -all] [var [...]] * If one or more variable names are specified, show information * named UEFI variables, otherwise show all the UEFI variables. + * By default, only variable names are shown. Use -v for verbose output. */ int do_env_print_efi(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { const efi_guid_t *guid_p = NULL; efi_guid_t guid; - bool verbose = true; + bool verbose = false; + bool nodump = false; efi_status_t ret; /* Initialize EFI drivers */ @@ -230,14 +240,17 @@ int do_env_print_efi(struct cmd_tbl *cmdtp, int flag, int argc, return CMD_RET_USAGE; guid_p = (const efi_guid_t *)guid.b; } else if (!strcmp(argv[0], "-n")) { - verbose = false; + verbose = true; + nodump = true; + } else if (!strcmp(argv[0], "-v")) { + verbose = true; } else { return CMD_RET_USAGE; } } /* enumerate and show all UEFI variables */ - return efi_dump_var_all(argc, argv, guid_p, verbose); + return efi_dump_var_all(argc, argv, guid_p, verbose, nodump); } /** diff --git a/doc/usage/cmd/env.rst b/doc/usage/cmd/env.rst index b65d85b6681..a1d90c6fca3 100644 --- a/doc/usage/cmd/env.rst +++ b/doc/usage/cmd/env.rst @@ -25,7 +25,7 @@ Synopsis env info [-d] [-p] [-q] env load env print [-a | name ...] - env print -e [-guid guid] [-n] [name ...] + env print -e [-guid guid] [-n] [-v] [name ...] env run var [...] env save env select [target] @@ -232,7 +232,10 @@ in UEFI variables. print only the UEFI variables matching this GUID (any by default) with guid format = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx". \-n - suppress dumping variable's value for UEFI. + don't show hexadecimal dump of value for UEFI variables. + \-v + show verbose output for UEFI variables including GUID, attributes, data + size and hexadecimal dump of value. Run ~~~ diff --git a/doc/usage/cmd/printenv.rst b/doc/usage/cmd/printenv.rst index dfdb3624934..cecfcf8bcda 100644 --- a/doc/usage/cmd/printenv.rst +++ b/doc/usage/cmd/printenv.rst @@ -12,7 +12,7 @@ Synopsis :: printenv [-a] [name ...] - printenv -e [-guid guid][-n] [name] + printenv -e [-guid guid][-n][-v] [name] Description ----------- @@ -32,6 +32,10 @@ The printenv command is used to print environment or UEFI variables. \-n don't show hexadecimal dump of value +\-v + show verbose output including GUID, attributes, data size and hexadecimal + dump of value (if not -n) + name Variable name. If no name is provided, all variables are printed. Multiple environment variable names may be specified. @@ -64,20 +68,24 @@ environment variables: Environment size: 653/8188 bytes => -The next example shows the effect of the *-n* flag when displaying an UEFI -variable and how to specify a vendor GUID: +The next example shows the different output modes when displaying UEFI +variables and how to specify a vendor GUID. By default, only the variable +name is shown. The *-v* flag shows full verbose output, while *-n* shows +details but omits the hexadecimal dump: :: - => printenv -e -guid 8be4df61-93ca-11d2-aa0d-00e098032b8c PlatformLangCodes + => printenv -e PlatformLangCodes + PlatformLangCodes + => printenv -e -v -n PlatformLangCodes PlatformLangCodes: 8be4df61-93ca-11d2-aa0d-00e098032b8c (EFI_GLOBAL_VARIABLE_GUID) BS|RT|RO, DataSize = 0x6 - 00000000: 65 6e 2d 55 53 00 en-US. - => printenv -e -n PlatformLangCodes + => printenv -e -v -guid 8be4df61-93ca-11d2-aa0d-00e098032b8c PlatformLangCodes PlatformLangCodes: 8be4df61-93ca-11d2-aa0d-00e098032b8c (EFI_GLOBAL_VARIABLE_GUID) BS|RT|RO, DataSize = 0x6 + 00000000: 65 6e 2d 55 53 00 en-US. => Configuration diff --git a/test/py/tests/test_efi_secboot/test_authvar.py b/test/py/tests/test_efi_secboot/test_authvar.py index 7b45f8fb814..3750f302dba 100644 --- a/test/py/tests/test_efi_secboot/test_authvar.py +++ b/test/py/tests/test_efi_secboot/test_authvar.py @@ -27,11 +27,11 @@ class TestEfiAuthVar(object): # Test Case 1a, Initial secure state output = ubman.run_command_list([ 'host bind 0 %s' % disk_img, - 'printenv -e SecureBoot']) + 'printenv -e -v SecureBoot']) assert '00000000: 00' in ''.join(output) output = ubman.run_command( - 'printenv -e SetupMode') + 'printenv -e -v SetupMode') assert '00000000: 01' in output with ubman.log.section('Test Case 1b'): @@ -46,14 +46,14 @@ class TestEfiAuthVar(object): output = ubman.run_command_list([ 'fatload host 0:1 4000000 PK.auth', 'setenv -e -nv -bs -rt -at -i 4000000:$filesize PK', - 'printenv -e -n PK']) + 'printenv -e -v PK']) assert 'PK:' in ''.join(output) output = ubman.run_command( - 'printenv -e SecureBoot') + 'printenv -e -v SecureBoot') assert '00000000: 01' in output output = ubman.run_command( - 'printenv -e SetupMode') + 'printenv -e -v SetupMode') assert '00000000: 00' in output with ubman.log.section('Test Case 1d'): @@ -78,11 +78,11 @@ class TestEfiAuthVar(object): output = ubman.run_command_list([ 'fatload host 0:1 4000000 KEK.auth', 'setenv -e -nv -bs -rt -at -i 4000000:$filesize KEK', - 'printenv -e -n KEK']) + 'printenv -e -v KEK']) assert 'KEK:' in ''.join(output) output = ubman.run_command( - 'printenv -e SecureBoot') + 'printenv -e -v SecureBoot') assert '00000000: 01' in output with ubman.log.section('Test Case 1f'): @@ -95,12 +95,12 @@ class TestEfiAuthVar(object): output = ubman.run_command_list([ 'fatload host 0:1 4000000 db.auth', 'setenv -e -nv -bs -rt -at -i 4000000:$filesize db', - 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) + 'printenv -e -v -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) assert 'Failed to set EFI variable' not in ''.join(output) assert 'db:' in ''.join(output) output = ubman.run_command( - 'printenv -e SecureBoot') + 'printenv -e -v SecureBoot') assert '00000000: 01' in output with ubman.log.section('Test Case 1g'): @@ -113,12 +113,12 @@ class TestEfiAuthVar(object): output = ubman.run_command_list([ 'fatload host 0:1 4000000 dbx.auth', 'setenv -e -nv -bs -rt -at -i 4000000:$filesize dbx', - 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f dbx']) + 'printenv -e -v -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f dbx']) assert 'Failed to set EFI variable' not in ''.join(output) assert 'dbx:' in ''.join(output) output = ubman.run_command( - 'printenv -e SecureBoot') + 'printenv -e -v SecureBoot') assert '00000000: 01' in output def test_efi_var_auth2(self, ubman, efi_boot_env): @@ -137,7 +137,7 @@ class TestEfiAuthVar(object): 'setenv -e -nv -bs -rt -at -i 4000000:$filesize KEK', 'fatload host 0:1 4000000 db.auth', 'setenv -e -nv -bs -rt -at -i 4000000:$filesize db', - 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) + 'printenv -e -v -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) assert 'Failed to set EFI variable' not in ''.join(output) assert 'db:' in ''.join(output) @@ -158,7 +158,7 @@ class TestEfiAuthVar(object): output = ubman.run_command_list([ 'fatload host 0:1 4000000 db1.auth', 'setenv -e -nv -bs -rt -at -i 4000000:$filesize db', - 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) + 'printenv -e -v -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) assert 'Failed to set EFI variable' not in ''.join(output) assert 'db:' in ''.join(output) @@ -178,7 +178,7 @@ class TestEfiAuthVar(object): 'setenv -e -nv -bs -rt -at -i 4000000:$filesize KEK', 'fatload host 0:1 4000000 db.auth', 'setenv -e -nv -bs -rt -at -i 4000000:$filesize db', - 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) + 'printenv -e -v -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) assert 'Failed to set EFI variable' not in ''.join(output) assert 'db:' in ''.join(output) @@ -199,7 +199,7 @@ class TestEfiAuthVar(object): output = ubman.run_command_list([ 'fatload host 0:1 4000000 db2.auth', 'setenv -e -nv -bs -rt -at -a -i 4000000:$filesize db', - 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) + 'printenv -e -v -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) assert 'Failed to set EFI variable' not in ''.join(output) assert 'db:' in ''.join(output) @@ -219,13 +219,13 @@ class TestEfiAuthVar(object): 'setenv -e -nv -bs -rt -at -i 4000000:$filesize KEK', 'fatload host 0:1 4000000 db.auth', 'setenv -e -nv -bs -rt -at -i 4000000:$filesize db', - 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) + 'printenv -e -v -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) assert 'Failed to set EFI variable' not in ''.join(output) assert 'db:' in ''.join(output) output = ubman.run_command_list([ 'setenv -e -nv -bs -rt db', - 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) + 'printenv -e -v -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) assert 'Failed to set EFI variable' in ''.join(output) assert 'db:' in ''.join(output) @@ -233,7 +233,7 @@ class TestEfiAuthVar(object): # Test Case 4b, update without correct signature/data output = ubman.run_command_list([ 'setenv -e -nv -bs -rt -at db', - 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) + 'printenv -e -v -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) assert 'Failed to set EFI variable' in ''.join(output) assert 'db:' in ''.join(output) @@ -253,14 +253,14 @@ class TestEfiAuthVar(object): 'setenv -e -nv -bs -rt -at -i 4000000:$filesize KEK', 'fatload host 0:1 4000000 db.auth', 'setenv -e -nv -bs -rt -at -i 4000000:$filesize db', - 'printenv -e -n PK']) + 'printenv -e -v PK']) assert 'Failed to set EFI variable' not in ''.join(output) assert 'PK:' in ''.join(output) output = ubman.run_command_list([ 'fatload host 0:1 4000000 PK_null.esl', 'setenv -e -nv -bs -rt -at -i 4000000:$filesize PK', - 'printenv -e -n PK']) + 'printenv -e -v PK']) assert 'Failed to set EFI variable' in ''.join(output) assert 'PK:' in ''.join(output) @@ -269,13 +269,13 @@ class TestEfiAuthVar(object): output = ubman.run_command_list([ 'fatload host 0:1 4000000 PK_null.auth', 'setenv -e -nv -bs -rt -at -i 4000000:$filesize PK', - 'printenv -e -n PK']) + 'printenv -e -v PK']) assert 'Failed to set EFI variable' not in ''.join(output) assert '\"PK\" not defined' in ''.join(output) output = ubman.run_command( - 'printenv -e SecureBoot') + 'printenv -e -v SecureBoot') assert '00000000: 00' in output output = ubman.run_command( - 'printenv -e SetupMode') + 'printenv -e -v SetupMode') assert '00000000: 01' in output -- 2.43.0

From: Simon Glass <sjg@chromium.org> This variable name is quite long. There is only one 'name' (the variable name) and it has to be u16 as it is an EFI variable. So rename it to 'name'. Signed-off-by: Simon Glass <sjg@chromium.org> --- cmd/nvedit_efi.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/cmd/nvedit_efi.c b/cmd/nvedit_efi.c index 12c98a5d5c4..0e4abf49fc0 100644 --- a/cmd/nvedit_efi.c +++ b/cmd/nvedit_efi.c @@ -146,48 +146,47 @@ out: static int efi_dump_var_all(int argc, char *const argv[], const efi_guid_t *guid_p, bool verbose, bool nodump) { - u16 *var_name16, *p; efi_uintn_t buf_size, size; efi_guid_t guid; efi_status_t ret; bool match = false; + u16 *name, *p; buf_size = 128; - var_name16 = malloc(buf_size); - if (!var_name16) + name = malloc(buf_size); + if (!name) return CMD_RET_FAILURE; - var_name16[0] = 0; + name[0] = 0; for (;;) { size = buf_size; - ret = efi_get_next_variable_name_int(&size, var_name16, - &guid); + ret = efi_get_next_variable_name_int(&size, name, &guid); if (ret == EFI_NOT_FOUND) break; if (ret == EFI_BUFFER_TOO_SMALL) { buf_size = size; - p = realloc(var_name16, buf_size); + p = realloc(name, buf_size); if (!p) { - free(var_name16); + free(name); return CMD_RET_FAILURE; } - var_name16 = p; - ret = efi_get_next_variable_name_int(&size, var_name16, + name = p; + ret = efi_get_next_variable_name_int(&size, name, &guid); } if (ret != EFI_SUCCESS) { - free(var_name16); + free(name); return CMD_RET_FAILURE; } if (guid_p && guidcmp(guid_p, &guid)) continue; - if (!argc || match_name(argc, argv, var_name16)) { + if (!argc || match_name(argc, argv, name)) { match = true; - efi_dump_single_var(var_name16, &guid, verbose, nodump); + efi_dump_single_var(name, &guid, verbose, nodump); } } - free(var_name16); + free(name); if (!match && argc == 1) { printf("Error: \"%s\" not defined\n", argv[0]); -- 2.43.0

From: Simon Glass <sjg@chromium.org> Rather than freeing the variable in several places, put it at the end. Assume failure by default, returning success only if all steps passed. Signed-off-by: Simon Glass <sjg@chromium.org> --- cmd/nvedit_efi.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/cmd/nvedit_efi.c b/cmd/nvedit_efi.c index 0e4abf49fc0..f2bba42850d 100644 --- a/cmd/nvedit_efi.c +++ b/cmd/nvedit_efi.c @@ -150,6 +150,7 @@ static int efi_dump_var_all(int argc, char *const argv[], efi_guid_t guid; efi_status_t ret; bool match = false; + bool ok = false; u16 *name, *p; buf_size = 128; @@ -166,18 +167,14 @@ static int efi_dump_var_all(int argc, char *const argv[], if (ret == EFI_BUFFER_TOO_SMALL) { buf_size = size; p = realloc(name, buf_size); - if (!p) { - free(name); - return CMD_RET_FAILURE; - } + if (!p) + goto fail; name = p; ret = efi_get_next_variable_name_int(&size, name, &guid); } - if (ret != EFI_SUCCESS) { - free(name); - return CMD_RET_FAILURE; - } + if (ret != EFI_SUCCESS) + goto fail; if (guid_p && guidcmp(guid_p, &guid)) continue; @@ -186,14 +183,18 @@ static int efi_dump_var_all(int argc, char *const argv[], efi_dump_single_var(name, &guid, verbose, nodump); } } - free(name); if (!match && argc == 1) { printf("Error: \"%s\" not defined\n", argv[0]); - return CMD_RET_FAILURE; + goto done; } - return CMD_RET_SUCCESS; + ok = true; +fail: +done: + free(name); + + return ok ? 0 : CMD_RET_FAILURE; } /** -- 2.43.0

From: Simon Glass <sjg@chromium.org> Rather than printing as we go, add variables to an alist so they can be printed when all variables are present. Signed-off-by: Simon Glass <sjg@chromium.org> --- cmd/nvedit_efi.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/cmd/nvedit_efi.c b/cmd/nvedit_efi.c index f2bba42850d..ce3ab9f785a 100644 --- a/cmd/nvedit_efi.c +++ b/cmd/nvedit_efi.c @@ -38,6 +38,17 @@ static const struct { {EFI_VARIABLE_READ_ONLY, "RO"}, }; +/** + * struct var_info - stores information about a single variable + * + * @name: Variable name (allocated) + * @guid: Variable guid + */ +struct var_info { + u16 *name; + efi_guid_t guid; +}; + /** * efi_dump_single_var() - show information about a UEFI variable * @@ -147,9 +158,10 @@ static int efi_dump_var_all(int argc, char *const argv[], const efi_guid_t *guid_p, bool verbose, bool nodump) { efi_uintn_t buf_size, size; + struct var_info *var; + struct alist vars; efi_guid_t guid; efi_status_t ret; - bool match = false; bool ok = false; u16 *name, *p; @@ -159,6 +171,7 @@ static int efi_dump_var_all(int argc, char *const argv[], return CMD_RET_FAILURE; name[0] = 0; + alist_init_struct(&vars, struct var_info); for (;;) { size = buf_size; ret = efi_get_next_variable_name_int(&size, name, &guid); @@ -179,20 +192,33 @@ static int efi_dump_var_all(int argc, char *const argv[], if (guid_p && guidcmp(guid_p, &guid)) continue; if (!argc || match_name(argc, argv, name)) { - match = true; - efi_dump_single_var(name, &guid, verbose, nodump); + struct var_info new_var; + + new_var.name = (u16 *)memdup(name, size); + if (!new_var.name) + goto fail; + new_var.guid = guid; + + if (!alist_add(&vars, new_var)) + goto fail; } } - if (!match && argc == 1) { + if (!vars.count && argc == 1) { printf("Error: \"%s\" not defined\n", argv[0]); goto done; } + alist_for_each(var, &vars) + efi_dump_single_var(var->name, &var->guid, verbose, nodump); + ok = true; fail: done: free(name); + alist_for_each(var, &vars) + free(var->name); + alist_uninit(&vars); return ok ? 0 : CMD_RET_FAILURE; } -- 2.43.0

From: Simon Glass <sjg@chromium.org> Add support for sorting EFI variables by name when using printenv -e. The -s flag sorts variables alphabetically before display, useful when dealing with large numbers of variables. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <sjg@chromium.org> --- cmd/nvedit.c | 5 +-- cmd/nvedit_efi.c | 31 +++++++++++++++-- doc/usage/cmd/env.rst | 4 ++- doc/usage/cmd/printenv.rst | 68 ++++++++++++++++++++++++++++++++++++-- 4 files changed, 99 insertions(+), 9 deletions(-) diff --git a/cmd/nvedit.c b/cmd/nvedit.c index 8dbe8a03fd5..f67c268da84 100644 --- a/cmd/nvedit.c +++ b/cmd/nvedit.c @@ -1174,7 +1174,7 @@ U_BOOT_LONGHELP(env, #endif "env print [-a | name ...] - print environment\n" #if defined(CONFIG_CMD_NVEDIT_EFI) - "env print -e [-guid guid] [-n] [-v] [name ...] print UEFI environment\n" + "env print -e [-guid guid] [-n] [-s] [-v] [name ...] print UEFI environment\n" #endif #if defined(CONFIG_CMD_RUN) "env run var [...] - run commands in an environment variable\n" @@ -1221,10 +1221,11 @@ U_BOOT_CMD_COMPLETE( "print environment variables", "[-a]\n - print [all] values of all environment variables\n" #if defined(CONFIG_CMD_NVEDIT_EFI) - "printenv -e [-guid guid][-n] [-v] [name ...]\n" + "printenv -e [-guid guid][-n] [-s] [-v] [name ...]\n" " - print UEFI variable 'name' or all the variables\n" " \"-guid\": GUID xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\n" " \"-n\": suppress dumping variable's value\n" + " \"-s\": sort variables by name\n" " \"-v\": show GUID, flags, size; also dump (without -n)\n" #endif "printenv name ...\n" diff --git a/cmd/nvedit_efi.c b/cmd/nvedit_efi.c index ce3ab9f785a..5616e73bcfd 100644 --- a/cmd/nvedit_efi.c +++ b/cmd/nvedit_efi.c @@ -15,6 +15,7 @@ #include <malloc.h> #include <mapmem.h> #include <rtc.h> +#include <sort.h> #include <u-boot/uuid.h> #include <linux/kernel.h> @@ -142,6 +143,21 @@ out: return result; } +/** + * var_info_cmp() - compare two var_info structures by name + * + * @a: First var_info structure + * @b: Second var_info structure + * Return: comparison result for qsort + */ +static int var_info_cmp(const void *a, const void *b) +{ + const struct var_info *va = a; + const struct var_info *vb = b; + + return u16_strcmp(va->name, vb->name); +} + /** * efi_dump_var_all() - show information about all the UEFI variables * @@ -150,12 +166,14 @@ out: * @guid_p: GUID to filter by, or NULL for all * @verbose: if true, show detailed information * @nodump: if true, don't show hexadecimal dump + * @sort: if true, sort variables by name before printing * Return: CMD_RET_SUCCESS on success, or CMD_RET_RET_FAILURE * * Show information encoded in all the UEFI variables */ static int efi_dump_var_all(int argc, char *const argv[], - const efi_guid_t *guid_p, bool verbose, bool nodump) + const efi_guid_t *guid_p, bool verbose, bool nodump, + bool sort) { efi_uintn_t buf_size, size; struct var_info *var; @@ -209,6 +227,9 @@ static int efi_dump_var_all(int argc, char *const argv[], goto done; } + if (sort && vars.count > 1) + qsort(vars.data, vars.count, sizeof(struct var_info), var_info_cmp); + alist_for_each(var, &vars) efi_dump_single_var(var->name, &var->guid, verbose, nodump); @@ -233,10 +254,11 @@ done: * Return: CMD_RET_SUCCESS on success, or CMD_RET_RET_FAILURE * * This function is for "env print -e" or "printenv -e" command: - * => env print -e [-v] [-guid <guid> | -all] [var [...]] + * => env print -e [-v] [-s] [-guid <guid> | -all] [var [...]] * If one or more variable names are specified, show information * named UEFI variables, otherwise show all the UEFI variables. * By default, only variable names are shown. Use -v for verbose output. + * Use -s to sort variables by name. */ int do_env_print_efi(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) @@ -245,6 +267,7 @@ int do_env_print_efi(struct cmd_tbl *cmdtp, int flag, int argc, efi_guid_t guid; bool verbose = false; bool nodump = false; + bool sort = false; efi_status_t ret; /* Initialize EFI drivers */ @@ -270,13 +293,15 @@ int do_env_print_efi(struct cmd_tbl *cmdtp, int flag, int argc, nodump = true; } else if (!strcmp(argv[0], "-v")) { verbose = true; + } else if (!strcmp(argv[0], "-s")) { + sort = true; } else { return CMD_RET_USAGE; } } /* enumerate and show all UEFI variables */ - return efi_dump_var_all(argc, argv, guid_p, verbose, nodump); + return efi_dump_var_all(argc, argv, guid_p, verbose, nodump, sort); } /** diff --git a/doc/usage/cmd/env.rst b/doc/usage/cmd/env.rst index a1d90c6fca3..c96dd038f02 100644 --- a/doc/usage/cmd/env.rst +++ b/doc/usage/cmd/env.rst @@ -25,7 +25,7 @@ Synopsis env info [-d] [-p] [-q] env load env print [-a | name ...] - env print -e [-guid guid] [-n] [-v] [name ...] + env print -e [-guid guid] [-n] [-s] [-v] [name ...] env run var [...] env save env select [target] @@ -233,6 +233,8 @@ in UEFI variables. with guid format = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx". \-n don't show hexadecimal dump of value for UEFI variables. + \-s + sort UEFI variables by name before displaying. \-v show verbose output for UEFI variables including GUID, attributes, data size and hexadecimal dump of value. diff --git a/doc/usage/cmd/printenv.rst b/doc/usage/cmd/printenv.rst index cecfcf8bcda..5ba3a6e63f7 100644 --- a/doc/usage/cmd/printenv.rst +++ b/doc/usage/cmd/printenv.rst @@ -12,7 +12,7 @@ Synopsis :: printenv [-a] [name ...] - printenv -e [-guid guid][-n][-v] [name] + printenv -e [-guid guid][-n][-s][-v] [name] Description ----------- @@ -32,6 +32,9 @@ The printenv command is used to print environment or UEFI variables. \-n don't show hexadecimal dump of value +\-s + sort variables by name before displaying + \-v show verbose output including GUID, attributes, data size and hexadecimal dump of value (if not -n) @@ -71,7 +74,8 @@ environment variables: The next example shows the different output modes when displaying UEFI variables and how to specify a vendor GUID. By default, only the variable name is shown. The *-v* flag shows full verbose output, while *-n* shows -details but omits the hexadecimal dump: +details but omits the hexadecimal dump. The *-s* flag sorts variables by +name: :: @@ -86,7 +90,65 @@ details but omits the hexadecimal dump: 8be4df61-93ca-11d2-aa0d-00e098032b8c (EFI_GLOBAL_VARIABLE_GUID) BS|RT|RO, DataSize = 0x6 00000000: 65 6e 2d 55 53 00 en-US. - => + => print -e -s + 525400123456 + 525400123456 + Attempt 1 + Attempt 2 + Attempt 3 + Attempt 4 + Attempt 5 + Attempt 6 + Attempt 7 + Attempt 8 + Boot0000 + Boot0001 + Boot0002 + Boot0003 + BootCurrent + BootOptionSupport + BootOrder + ClientId + ConIn + ConInDev + ConOut + ConOutDev + ErrOut + ErrOutDev + HDDP + InitialAttemptOrder + Key0000 + Key0001 + Lang + LangCodes + MTC + MemoryTypeInformation + OsIndicationsSupported + PlatformLang + PlatformLangCodes + PlatformRecovery0000 + SbatLevel + Timeout + VarErrorFlag + cat + cd.. + cd\ + copy + debuglasterror + del + dir + lasterror + md + mem + mount + move + nonesting + path + profiles + ren + uefishellsupport + uefishellversion + uefiversion Configuration ------------- -- 2.43.0
participants (1)
-
Simon Glass