efibootmgr: Add --efidev (-u) to discover UEFI's device path to a dev or file

"efibootmgr --efidev unix-path" will return the UEFI device-path to the
file or device specified by unix-path. It's useful for debugging, but
may also be useful for scripting.

Sponsored by:		Netflix
Reviewed by:		corvink, manu
Differential Revision:	https://reviews.freebsd.org/D38617
This commit is contained in:
Warner Losh 2023-02-16 08:53:45 -07:00
parent 57d5ca4eeb
commit 9a79152994
2 changed files with 38 additions and 4 deletions

View file

@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd April 3, 2022
.Dd February 15, 2023
.Dt EFIBOOTMGR 8
.Os
.Sh NAME
@ -69,6 +69,7 @@
.Fl t Ar timeout
.Nm
.Fl T
.Nm Fl u Ar unix-path
.Sh "DESCRIPTION"
The
.Nm
@ -174,6 +175,9 @@ Set the bootmenu timeout value.
Delete the
.Cm BootTimeout
variable.
.It Fl u -efidev Ar unix-path
Displays the UEFI device path of
.Ar unix-path .
.It Fl v -verbose
Display the device path of boot entries in the output.
.El

View file

@ -70,6 +70,7 @@ __FBSDID("$FreeBSD$");
#define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001
typedef struct _bmgr_opts {
char *dev;
char *env;
char *loader;
char *label;
@ -85,6 +86,7 @@ typedef struct _bmgr_opts {
bool dry_run;
bool device_path;
bool esp_device;
bool find_dev;
bool fw_ui;
bool no_fw_ui;
bool has_bootnum;
@ -114,6 +116,7 @@ static struct option lopts[] = {
{"dry-run", no_argument, NULL, 'D'},
{"env", required_argument, NULL, 'e'},
{"esp", no_argument, NULL, 'E'},
{"efidev", required_argument, NULL, 'u'},
{"fw-ui", no_argument, NULL, 'f'},
{"no-fw-ui", no_argument, NULL, 'F'},
{"help", no_argument, NULL, 'h'},
@ -284,6 +287,9 @@ parse_args(int argc, char *argv[])
opts.set_timeout = true;
opts.timeout = strtoul(optarg, NULL, 10);
break;
case 'u':
opts.find_dev = true;
opts.dev = strdup(optarg);
case 'v':
opts.verbose = true;
break;
@ -996,7 +1002,7 @@ report_esp_device(bool do_dp, bool do_unix)
char *name, *dev, *relpath, *abspath;
uint8_t *walker, *ep;
efi_char *descr;
efidp dp, edp;
efidp dp;
char buf[PATH_MAX];
if (do_dp && do_unix)
@ -1026,7 +1032,6 @@ report_esp_device(bool do_dp, bool do_unix)
// Now we have fplen bytes worth of file path stuff
dp = (efidp)walker;
walker += fplen;
edp = (efidp)walker;
if (walker > ep)
errx(1, "malformed boot variable %s", name);
if (do_dp) {
@ -1068,6 +1073,26 @@ set_boot_to_fw_ui(bool to_fw)
errx(1, "failed to set boot to fw ui");
}
static void
find_efi_device(const char *path)
{
efidp dp = NULL;
size_t len;
int ret;
char buf[1024];
ret = efivar_unix_path_to_device_path(path, &dp);
if (ret != 0)
errc(1, ret,
"Cannot translate path '%s' to UEFI", path);
len = efidp_size(dp);
if (len > MAX_DP_LEN)
errx(1, "Resulting device path too long.");
efidp_format_device_path(buf, sizeof(buf), dp, len);
printf("%s -> %s\n", path, buf);
exit (0);
}
int
main(int argc, char *argv[])
{
@ -1075,7 +1100,10 @@ main(int argc, char *argv[])
memset(&opts, 0, sizeof (bmgr_opts_t));
parse_args(argc, argv);
if (!efi_variables_supported())
/*
* find_dev can operate without any efi variables
*/
if (!efi_variables_supported() && !opts.find_dev)
errx(1, "efi variables not supported on this system. root? kldload efirt?");
read_vars();
@ -1107,6 +1135,8 @@ main(int argc, char *argv[])
set_boot_to_fw_ui(true);
else if (opts.no_fw_ui)
set_boot_to_fw_ui(false);
else if (opts.find_dev)
find_efi_device(opts.dev);
print_boot_vars(opts.verbose);
}