Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 20 Nov 2019 23:58:36 +0000 (UTC)
From:      Warner Losh <imp@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r354925 - head/usr.sbin/efibootmgr
Message-ID:  <201911202358.xAKNwaUP045154@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: imp
Date: Wed Nov 20 23:58:36 2019
New Revision: 354925
URL: https://svnweb.freebsd.org/changeset/base/354925

Log:
  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

Modified:
  head/usr.sbin/efibootmgr/efibootmgr.8
  head/usr.sbin/efibootmgr/efibootmgr.c

Modified: head/usr.sbin/efibootmgr/efibootmgr.8
==============================================================================
--- head/usr.sbin/efibootmgr/efibootmgr.8	Wed Nov 20 23:56:20 2019	(r354924)
+++ head/usr.sbin/efibootmgr/efibootmgr.8	Wed Nov 20 23:58:36 2019	(r354925)
@@ -49,7 +49,12 @@
 .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
 .Nm
@@ -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

Modified: head/usr.sbin/efibootmgr/efibootmgr.c
==============================================================================
--- head/usr.sbin/efibootmgr/efibootmgr.c	Wed Nov 20 23:56:20 2019	(r354924)
+++ head/usr.sbin/efibootmgr/efibootmgr.c	Wed Nov 20 23:58:36 2019	(r354925)
@@ -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);
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201911202358.xAKNwaUP045154>