Index: head/usr.sbin/efibootmgr/efibootmgr.8 =================================================================== --- head/usr.sbin/efibootmgr/efibootmgr.8 +++ head/usr.sbin/efibootmgr/efibootmgr.8 @@ -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 @@ 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 Index: head/usr.sbin/efibootmgr/efibootmgr.c =================================================================== --- head/usr.sbin/efibootmgr/efibootmgr.c +++ head/usr.sbin/efibootmgr/efibootmgr.c @@ -81,6 +81,8 @@ 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 @@ bool set_inactive; bool set_timeout; int timeout; + bool unix_path; bool verbose; } bmgr_opts_t; @@ -103,14 +106,17 @@ {"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 @@ { 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 @@ 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 @@ 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 @@ 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 @@ 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); }