aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWarner Losh <imp@FreeBSD.org>2019-11-20 23:58:36 +0000
committerWarner Losh <imp@FreeBSD.org>2019-11-20 23:58:36 +0000
commit1cdb8eb8fe16025c151957b05202320e3f1c9a78 (patch)
tree7920f3550993a689a8d2fc576d3ad8f4bb788e70
parent9af6c78cd43b18e169f10802142c61638bd62bed (diff)
downloadsrc-1cdb8eb8fe1.tar.gz
src-1cdb8eb8fe1.zip
Add --esp/-E argument to print the currently booted ESP
Add code to decode the BootCurrent and BootXXXX variable it points at to deduce the ESP used to boot the system. By default, it prints the path to that device. With --unix-path (-p) it will instead print the current mount point for the ESP, if any (or an error). With --device-path (-d) it wil print the UEFI device path for the ESP. Note: This is the best guess based on the UEFI variables. If the ESP is part of a gmirror, etc, that won't be reported. If by some weird chance there was a complicated series of chain boots, this may not be what you want. For setups that don't add layers on top of the raw devices, it is accurate. Differential Revision: https://reviews.freebsd.org/D22432
Notes
Notes: svn path=/head/; revision=354925
-rw-r--r--usr.sbin/efibootmgr/efibootmgr.820
-rw-r--r--usr.sbin/efibootmgr/efibootmgr.c85
2 files changed, 104 insertions, 1 deletions
diff --git a/usr.sbin/efibootmgr/efibootmgr.8 b/usr.sbin/efibootmgr/efibootmgr.8
index 1a7776b92697..a36d642e85df 100644
--- a/usr.sbin/efibootmgr/efibootmgr.8
+++ b/usr.sbin/efibootmgr/efibootmgr.8
@@ -49,6 +49,11 @@
.Op Fl b Ar bootnum
.Op Fl k Ar kernel
.Op Fl L Ar label
+.Op Fl e Ar env
+.Nm
+.Fl E
+.Op Fl d
+.Op Fl p
.Nm
.Fl n
.Fl b Ar bootnum
@@ -111,6 +116,21 @@ Create a new
variable.
.It Fl D -dry-run
Process but do not change any variables.
+.It Fl E -esp
+Print the
+.Fx
+path to the ESP device, derived from the EFI variables
+.Va BootCurrent
+and
+.Va BootXXXX .
+This is the ESP partition used by UEFI to boot the current
+instance of the system.
+If
+.Fl d -device-path
+is specified, the UEFI device path to the ESP is reported instead.
+If
+.Fl p -unix-path
+is specified, the mount point of the ESP is reported instead.
.It Fl k -kernel Ar kernel
The path to and name of the kernel.
.It Fl l -loader Ar loader
diff --git a/usr.sbin/efibootmgr/efibootmgr.c b/usr.sbin/efibootmgr/efibootmgr.c
index e62ff6b50588..0d3e0635cb10 100644
--- a/usr.sbin/efibootmgr/efibootmgr.c
+++ b/usr.sbin/efibootmgr/efibootmgr.c
@@ -81,6 +81,8 @@ typedef struct _bmgr_opts {
bool delete_bootnext;
bool del_timeout;
bool dry_run;
+ bool device_path;
+ bool esp_device;
bool has_bootnum;
bool once;
int cp_src;
@@ -89,6 +91,7 @@ typedef struct _bmgr_opts {
bool set_inactive;
bool set_timeout;
int timeout;
+ bool unix_path;
bool verbose;
} bmgr_opts_t;
@@ -103,14 +106,17 @@ static struct option lopts[] = {
{"del-timout", no_argument, NULL, 'T'},
{"delete", no_argument, NULL, 'B'},
{"delete-bootnext", no_argument, NULL, 'N'},
+ {"device-path", no_argument, NULL, 'd'},
{"dry-run", no_argument, NULL, 'D'},
{"env", required_argument, NULL, 'e'},
+ {"esp", no_argument, NULL, 'E'},
{"help", no_argument, NULL, 'h'},
{"kernel", required_argument, NULL, 'k'},
{"label", required_argument, NULL, 'L'},
{"loader", required_argument, NULL, 'l'},
{"once", no_argument, NULL, 'O'},
{"set-timeout", required_argument, NULL, 't'},
+ {"unix-path", no_argument, NULL, 'p'},
{"verbose", no_argument, NULL, 'v'},
{ NULL, 0, NULL, 0}
};
@@ -191,7 +197,7 @@ parse_args(int argc, char *argv[])
{
int ch;
- while ((ch = getopt_long(argc, argv, "AaBb:C:cDe:hk:L:l:NnOo:Tt:v",
+ while ((ch = getopt_long(argc, argv, "AaBb:C:cdDe:Ehk:L:l:NnOo:pTt:v",
lopts, NULL)) != -1) {
switch (ch) {
case 'A':
@@ -216,10 +222,16 @@ parse_args(int argc, char *argv[])
case 'D': /* should be remove dups XXX */
opts.dry_run = true;
break;
+ case 'd':
+ opts.device_path = true;
+ break;
case 'e':
free(opts.env);
opts.env = strdup(optarg);
break;
+ case 'E':
+ opts.esp_device = true;
+ break;
case 'h':
default:
errx(1, "%s", USAGE);
@@ -250,6 +262,9 @@ parse_args(int argc, char *argv[])
free(opts.order);
opts.order = strdup(optarg);
break;
+ case 'p':
+ opts.unix_path = true;
+ break;
case 'T':
opts.del_timeout = true;
break;
@@ -906,6 +921,72 @@ handle_timeout(int to)
errx(1, "Can't set Timeout for booting.");
}
+static void
+report_esp_device(bool do_dp, bool do_unix)
+{
+ uint8_t *data;
+ size_t size, len;
+ uint32_t attrs;
+ int ret;
+ uint16_t current, fplen;
+ char *name, *dev, *relpath, *abspath;
+ uint8_t *walker, *ep;
+ efi_char *descr;
+ efidp dp, edp;
+ char buf[PATH_MAX];
+
+ if (do_dp && do_unix)
+ errx(1, "Can't report both UEFI device-path and Unix path together");
+
+ ret = efi_get_variable(EFI_GLOBAL_GUID, "BootCurrent", &data, &size,&attrs);
+ if (ret < 0)
+ err(1, "Can't get BootCurrent");
+ current = le16dec(data);
+ if (asprintf(&name, "Boot%04X", current) < 0)
+ err(1, "Can't format boot var\n");
+ if (efi_get_variable(EFI_GLOBAL_GUID, name, &data, &size, NULL) < 0)
+ err(1, "Can't retrieve EFI var %s", name);
+ // First 4 bytes are attribute flags
+ walker = data;
+ ep = walker + size;
+ walker += sizeof(uint32_t);
+ // Next two bytes are length of the file paths
+ fplen = le16dec(walker);
+ walker += sizeof(fplen);
+ // Next we have a 0 terminated UCS2 string that we know to be aligned
+ descr = (efi_char *)(intptr_t)(void *)walker;
+ len = ucs2len(descr); // XXX need to sanity check that len < (datalen - (ep - walker) / 2)
+ walker += (len + 1) * sizeof(efi_char);
+ if (walker > ep)
+ errx(1, "malformed boot variable %s", name);
+ // 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) {
+ efidp_format_device_path_node(buf, sizeof(buf), dp);
+ printf("%s\n", buf);
+ exit(0);
+ }
+ if (efivar_device_path_to_unix_path(dp, &dev, &relpath, &abspath) < 0)
+ errx(1, "Can't convert to unix path");
+ if (do_unix) {
+ if (abspath == NULL)
+ errx(1, "Can't find where %s:%s is mounted",
+ dev, relpath);
+ abspath[strlen(abspath) - strlen(relpath) - 1] = '\0';
+ printf("%s\n", abspath);
+ } else {
+ printf("%s\n", dev);
+ }
+ free(dev);
+ free(relpath);
+ free(abspath);
+ exit(0);
+}
+
int
main(int argc, char *argv[])
{
@@ -938,6 +1019,8 @@ main(int argc, char *argv[])
delete_timeout();
else if (opts.set_timeout)
handle_timeout(opts.timeout);
+ else if (opts.esp_device)
+ report_esp_device(opts.device_path, opts.unix_path);
print_boot_vars(opts.verbose);
}