'src/boot/bootctl-reboot-to-firmware.h',
'src/boot/bootctl-set-efivar.c',
'src/boot/bootctl-set-efivar.h',
+ 'src/boot/bootctl-status.c',
+ 'src/boot/bootctl-status.h',
'src/boot/bootctl-systemd-efi-options.c',
'src/boot/bootctl-systemd-efi-options.h',
'src/boot/bootctl-util.c',
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include "bootctl.h"
+#include "bootctl-status.h"
+#include "bootctl-util.h"
+#include "bootspec.h"
+#include "chase-symlinks.h"
+#include "devnum-util.h"
+#include "dirent-util.h"
+#include "efi-api.h"
+#include "efi-loader.h"
+#include "errno-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "find-esp.h"
+#include "path-util.h"
+#include "pretty-print.h"
+#include "terminal-util.h"
+#include "tpm2-util.h"
+
+static int boot_config_load_and_select(
+ BootConfig *config,
+ const char *esp_path,
+ dev_t esp_devid,
+ const char *xbootldr_path,
+ dev_t xbootldr_devid) {
+
+ int r;
+
+ /* If XBOOTLDR and ESP actually refer to the same block device, suppress XBOOTLDR, since it would
+ * find the same entries twice. */
+ bool same = esp_path && xbootldr_path && devnum_set_and_equal(esp_devid, xbootldr_devid);
+
+ r = boot_config_load(config, esp_path, same ? NULL : xbootldr_path);
+ if (r < 0)
+ return r;
+
+ if (!arg_root) {
+ _cleanup_strv_free_ char **efi_entries = NULL;
+
+ r = efi_loader_get_entries(&efi_entries);
+ if (r == -ENOENT || ERRNO_IS_NOT_SUPPORTED(r))
+ log_debug_errno(r, "Boot loader reported no entries.");
+ else if (r < 0)
+ log_warning_errno(r, "Failed to determine entries reported by boot loader, ignoring: %m");
+ else
+ (void) boot_config_augment_from_loader(config, efi_entries, /* only_auto= */ false);
+ }
+
+ return boot_config_select_special_entries(config, /* skip_efivars= */ !!arg_root);
+}
+
+static int status_entries(
+ const BootConfig *config,
+ const char *esp_path,
+ sd_id128_t esp_partition_uuid,
+ const char *xbootldr_path,
+ sd_id128_t xbootldr_partition_uuid) {
+
+ sd_id128_t dollar_boot_partition_uuid;
+ const char *dollar_boot_path;
+ int r;
+
+ assert(config);
+ assert(esp_path || xbootldr_path);
+
+ if (xbootldr_path) {
+ dollar_boot_path = xbootldr_path;
+ dollar_boot_partition_uuid = xbootldr_partition_uuid;
+ } else {
+ dollar_boot_path = esp_path;
+ dollar_boot_partition_uuid = esp_partition_uuid;
+ }
+
+ printf("%sBoot Loader Entries:%s\n"
+ " $BOOT: %s", ansi_underline(), ansi_normal(), dollar_boot_path);
+ if (!sd_id128_is_null(dollar_boot_partition_uuid))
+ printf(" (/dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR ")",
+ SD_ID128_FORMAT_VAL(dollar_boot_partition_uuid));
+ printf("\n\n");
+
+ if (config->default_entry < 0)
+ printf("%zu entries, no entry could be determined as default.\n", config->n_entries);
+ else {
+ printf("%sDefault Boot Loader Entry:%s\n", ansi_underline(), ansi_normal());
+
+ r = show_boot_entry(
+ boot_config_default_entry(config),
+ /* show_as_default= */ false,
+ /* show_as_selected= */ false,
+ /* show_discovered= */ false);
+ if (r > 0)
+ /* < 0 is already logged by the function itself, let's just emit an extra warning if
+ the default entry is broken */
+ printf("\nWARNING: default boot entry is broken\n");
+ }
+
+ return 0;
+}
+
+static int print_efi_option(uint16_t id, int *n_printed, bool in_order) {
+ _cleanup_free_ char *title = NULL;
+ _cleanup_free_ char *path = NULL;
+ sd_id128_t partition;
+ bool active;
+ int r;
+
+ assert(n_printed);
+
+ r = efi_get_boot_option(id, &title, &partition, &path, &active);
+ if (r == -ENOENT) {
+ log_debug_errno(r, "Boot option 0x%04X referenced but missing, ignoring: %m", id);
+ return 0;
+ }
+ if (r < 0)
+ return log_error_errno(r, "Failed to read boot option 0x%04X: %m", id);
+
+ /* print only configured entries with partition information */
+ if (!path || sd_id128_is_null(partition)) {
+ log_debug("Ignoring boot entry 0x%04X without partition information.", id);
+ return 0;
+ }
+
+ efi_tilt_backslashes(path);
+
+ if (*n_printed == 0) /* Print section title before first entry */
+ printf("%sBoot Loaders Listed in EFI Variables:%s\n", ansi_underline(), ansi_normal());
+
+ printf(" Title: %s%s%s\n", ansi_highlight(), strna(title), ansi_normal());
+ printf(" ID: 0x%04X\n", id);
+ printf(" Status: %sactive%s\n", active ? "" : "in", in_order ? ", boot-order" : "");
+ printf(" Partition: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "\n",
+ SD_ID128_FORMAT_VAL(partition));
+ printf(" File: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), path);
+ printf("\n");
+
+ (*n_printed)++;
+ return 1;
+}
+
+static int status_variables(void) {
+ _cleanup_free_ uint16_t *options = NULL, *order = NULL;
+ int n_options, n_order, n_printed = 0;
+
+ n_options = efi_get_boot_options(&options);
+ if (n_options == -ENOENT)
+ return log_error_errno(n_options,
+ "Failed to access EFI variables, efivarfs"
+ " needs to be available at /sys/firmware/efi/efivars/.");
+ if (n_options < 0)
+ return log_error_errno(n_options, "Failed to read EFI boot entries: %m");
+
+ n_order = efi_get_boot_order(&order);
+ if (n_order == -ENOENT)
+ n_order = 0;
+ else if (n_order < 0)
+ return log_error_errno(n_order, "Failed to read EFI boot order: %m");
+
+ /* print entries in BootOrder first */
+ for (int i = 0; i < n_order; i++)
+ (void) print_efi_option(order[i], &n_printed, /* in_order= */ true);
+
+ /* print remaining entries */
+ for (int i = 0; i < n_options; i++) {
+ for (int j = 0; j < n_order; j++)
+ if (options[i] == order[j])
+ goto next_option;
+
+ (void) print_efi_option(options[i], &n_printed, /* in_order= */ false);
+
+ next_option:
+ continue;
+ }
+
+ if (n_printed == 0)
+ printf("No boot loaders listed in EFI Variables.\n\n");
+
+ return 0;
+}
+
+static int enumerate_binaries(
+ const char *esp_path,
+ const char *path,
+ const char *prefix,
+ char **previous,
+ bool *is_first) {
+
+ _cleanup_closedir_ DIR *d = NULL;
+ _cleanup_free_ char *p = NULL;
+ int c = 0, r;
+
+ assert(esp_path);
+ assert(path);
+ assert(previous);
+ assert(is_first);
+
+ r = chase_symlinks_and_opendir(path, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &p, &d);
+ if (r == -ENOENT)
+ return 0;
+ if (r < 0)
+ return log_error_errno(r, "Failed to read \"%s/%s\": %m", esp_path, path);
+
+ FOREACH_DIRENT(de, d, break) {
+ _cleanup_free_ char *v = NULL;
+ _cleanup_close_ int fd = -1;
+
+ if (!endswith_no_case(de->d_name, ".efi"))
+ continue;
+
+ if (prefix && !startswith_no_case(de->d_name, prefix))
+ continue;
+
+ fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to open \"%s/%s\" for reading: %m", p, de->d_name);
+
+ r = get_file_version(fd, &v);
+ if (r < 0)
+ return r;
+
+ if (*previous) { /* let's output the previous entry now, since now we know that there will be one more, and can draw the tree glyph properly */
+ printf(" %s %s%s\n",
+ *is_first ? "File:" : " ",
+ special_glyph(SPECIAL_GLYPH_TREE_BRANCH), *previous);
+ *is_first = false;
+ *previous = mfree(*previous);
+ }
+
+ /* Do not output this entry immediately, but store what should be printed in a state
+ * variable, because we only will know the tree glyph to print (branch or final edge) once we
+ * read one more entry */
+ if (r > 0)
+ r = asprintf(previous, "/%s/%s (%s%s%s)", path, de->d_name, ansi_highlight(), v, ansi_normal());
+ else
+ r = asprintf(previous, "/%s/%s", path, de->d_name);
+ if (r < 0)
+ return log_oom();
+
+ c++;
+ }
+
+ return c;
+}
+
+static int status_binaries(const char *esp_path, sd_id128_t partition) {
+ _cleanup_free_ char *last = NULL;
+ bool is_first = true;
+ int r, k;
+
+ printf("%sAvailable Boot Loaders on ESP:%s\n", ansi_underline(), ansi_normal());
+
+ if (!esp_path) {
+ printf(" ESP: Cannot find or access mount point of ESP.\n\n");
+ return -ENOENT;
+ }
+
+ printf(" ESP: %s", esp_path);
+ if (!sd_id128_is_null(partition))
+ printf(" (/dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR ")", SD_ID128_FORMAT_VAL(partition));
+ printf("\n");
+
+ r = enumerate_binaries(esp_path, "EFI/systemd", NULL, &last, &is_first);
+ if (r < 0) {
+ printf("\n");
+ return r;
+ }
+
+ k = enumerate_binaries(esp_path, "EFI/BOOT", "boot", &last, &is_first);
+ if (k < 0) {
+ printf("\n");
+ return k;
+ }
+
+ if (last) /* let's output the last entry now, since now we know that there will be no more, and can draw the tree glyph properly */
+ printf(" %s %s%s\n",
+ is_first ? "File:" : " ",
+ special_glyph(SPECIAL_GLYPH_TREE_RIGHT), last);
+
+ if (r == 0 && !arg_quiet)
+ log_info("systemd-boot not installed in ESP.");
+ if (k == 0 && !arg_quiet)
+ log_info("No default/fallback boot loader installed in ESP.");
+
+ printf("\n");
+ return 0;
+}
+
+static void read_efi_var(const char *variable, char **ret) {
+ int r;
+
+ r = efi_get_variable_string(variable, ret);
+ if (r < 0 && r != -ENOENT)
+ log_warning_errno(r, "Failed to read EFI variable %s: %m", variable);
+}
+
+static void print_yes_no_line(bool first, bool good, const char *name) {
+ printf("%s%s %s\n",
+ first ? " Features: " : " ",
+ COLOR_MARK_BOOL(good),
+ name);
+}
+
+int verb_status(int argc, char *argv[], void *userdata) {
+ sd_id128_t esp_uuid = SD_ID128_NULL, xbootldr_uuid = SD_ID128_NULL;
+ dev_t esp_devid = 0, xbootldr_devid = 0;
+ int r, k;
+
+ r = acquire_esp(/* unprivileged_mode= */ geteuid() != 0, /* graceful= */ false, NULL, NULL, NULL, &esp_uuid, &esp_devid);
+ if (arg_print_esp_path) {
+ if (r == -EACCES) /* If we couldn't acquire the ESP path, log about access errors (which is the only
+ * error the find_esp_and_warn() won't log on its own) */
+ return log_error_errno(r, "Failed to determine ESP location: %m");
+ if (r < 0)
+ return r;
+
+ puts(arg_esp_path);
+ }
+
+ r = acquire_xbootldr(/* unprivileged_mode= */ geteuid() != 0, &xbootldr_uuid, &xbootldr_devid);
+ if (arg_print_dollar_boot_path) {
+ if (r == -EACCES)
+ return log_error_errno(r, "Failed to determine XBOOTLDR partition: %m");
+ if (r < 0)
+ return r;
+
+ const char *path = arg_dollar_boot_path();
+ if (!path)
+ return log_error_errno(SYNTHETIC_ERRNO(EACCES), "Failed to determine XBOOTLDR location: %m");
+
+ puts(path);
+ }
+
+ if (arg_print_esp_path || arg_print_dollar_boot_path)
+ return 0;
+
+ r = 0; /* If we couldn't determine the path, then don't consider that a problem from here on, just
+ * show what we can show */
+
+ pager_open(arg_pager_flags);
+
+ if (!arg_root && is_efi_boot()) {
+ static const struct {
+ uint64_t flag;
+ const char *name;
+ } loader_flags[] = {
+ { EFI_LOADER_FEATURE_BOOT_COUNTING, "Boot counting" },
+ { EFI_LOADER_FEATURE_CONFIG_TIMEOUT, "Menu timeout control" },
+ { EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT, "One-shot menu timeout control" },
+ { EFI_LOADER_FEATURE_ENTRY_DEFAULT, "Default entry control" },
+ { EFI_LOADER_FEATURE_ENTRY_ONESHOT, "One-shot entry control" },
+ { EFI_LOADER_FEATURE_XBOOTLDR, "Support for XBOOTLDR partition" },
+ { EFI_LOADER_FEATURE_RANDOM_SEED, "Support for passing random seed to OS" },
+ { EFI_LOADER_FEATURE_LOAD_DRIVER, "Load drop-in drivers" },
+ { EFI_LOADER_FEATURE_SORT_KEY, "Support Type #1 sort-key field" },
+ { EFI_LOADER_FEATURE_SAVED_ENTRY, "Support @saved pseudo-entry" },
+ { EFI_LOADER_FEATURE_DEVICETREE, "Support Type #1 devicetree field" },
+ };
+ static const struct {
+ uint64_t flag;
+ const char *name;
+ } stub_flags[] = {
+ { EFI_STUB_FEATURE_REPORT_BOOT_PARTITION, "Stub sets ESP information" },
+ { EFI_STUB_FEATURE_PICK_UP_CREDENTIALS, "Picks up credentials from boot partition" },
+ { EFI_STUB_FEATURE_PICK_UP_SYSEXTS, "Picks up system extension images from boot partition" },
+ { EFI_STUB_FEATURE_THREE_PCRS, "Measures kernel+command line+sysexts" },
+ { EFI_STUB_FEATURE_RANDOM_SEED, "Support for passing random seed to OS" },
+ };
+ _cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL;
+ sd_id128_t loader_part_uuid = SD_ID128_NULL;
+ uint64_t loader_features = 0, stub_features = 0;
+ Tpm2Support s;
+ int have;
+
+ read_efi_var(EFI_LOADER_VARIABLE(LoaderFirmwareType), &fw_type);
+ read_efi_var(EFI_LOADER_VARIABLE(LoaderFirmwareInfo), &fw_info);
+ read_efi_var(EFI_LOADER_VARIABLE(LoaderInfo), &loader);
+ read_efi_var(EFI_LOADER_VARIABLE(StubInfo), &stub);
+ read_efi_var(EFI_LOADER_VARIABLE(LoaderImageIdentifier), &loader_path);
+ (void) efi_loader_get_features(&loader_features);
+ (void) efi_stub_get_features(&stub_features);
+
+ if (loader_path)
+ efi_tilt_backslashes(loader_path);
+
+ k = efi_loader_get_device_part_uuid(&loader_part_uuid);
+ if (k < 0 && k != -ENOENT)
+ r = log_warning_errno(k, "Failed to read EFI variable LoaderDevicePartUUID: %m");
+
+ SecureBootMode secure = efi_get_secure_boot_mode();
+ printf("%sSystem:%s\n", ansi_underline(), ansi_normal());
+ printf(" Firmware: %s%s (%s)%s\n", ansi_highlight(), strna(fw_type), strna(fw_info), ansi_normal());
+ printf(" Firmware Arch: %s\n", get_efi_arch());
+ printf(" Secure Boot: %sd (%s)\n",
+ enable_disable(IN_SET(secure, SECURE_BOOT_USER, SECURE_BOOT_DEPLOYED)),
+ secure_boot_mode_to_string(secure));
+
+ s = tpm2_support();
+ printf(" TPM2 Support: %s%s%s\n",
+ FLAGS_SET(s, TPM2_SUPPORT_FIRMWARE|TPM2_SUPPORT_DRIVER) ? ansi_highlight_green() :
+ (s & (TPM2_SUPPORT_FIRMWARE|TPM2_SUPPORT_DRIVER)) != 0 ? ansi_highlight_red() : ansi_highlight_yellow(),
+ FLAGS_SET(s, TPM2_SUPPORT_FIRMWARE|TPM2_SUPPORT_DRIVER) ? "yes" :
+ (s & TPM2_SUPPORT_FIRMWARE) ? "firmware only, driver unavailable" :
+ (s & TPM2_SUPPORT_DRIVER) ? "driver only, firmware unavailable" : "no",
+ ansi_normal());
+
+ k = efi_get_reboot_to_firmware();
+ if (k > 0)
+ printf(" Boot into FW: %sactive%s\n", ansi_highlight_yellow(), ansi_normal());
+ else if (k == 0)
+ printf(" Boot into FW: supported\n");
+ else if (k == -EOPNOTSUPP)
+ printf(" Boot into FW: not supported\n");
+ else {
+ errno = -k;
+ printf(" Boot into FW: %sfailed%s (%m)\n", ansi_highlight_red(), ansi_normal());
+ }
+ printf("\n");
+
+ printf("%sCurrent Boot Loader:%s\n", ansi_underline(), ansi_normal());
+ printf(" Product: %s%s%s\n", ansi_highlight(), strna(loader), ansi_normal());
+
+ for (size_t i = 0; i < ELEMENTSOF(loader_flags); i++)
+ print_yes_no_line(i == 0, FLAGS_SET(loader_features, loader_flags[i].flag), loader_flags[i].name);
+
+ sd_id128_t bootloader_esp_uuid;
+ bool have_bootloader_esp_uuid = efi_loader_get_device_part_uuid(&bootloader_esp_uuid) >= 0;
+
+ print_yes_no_line(false, have_bootloader_esp_uuid, "Boot loader sets ESP information");
+ if (have_bootloader_esp_uuid && !sd_id128_is_null(esp_uuid) &&
+ !sd_id128_equal(esp_uuid, bootloader_esp_uuid))
+ printf("WARNING: The boot loader reports a different ESP UUID than detected ("SD_ID128_UUID_FORMAT_STR" vs. "SD_ID128_UUID_FORMAT_STR")!\n",
+ SD_ID128_FORMAT_VAL(bootloader_esp_uuid),
+ SD_ID128_FORMAT_VAL(esp_uuid));
+
+ if (stub) {
+ printf(" Stub: %s\n", stub);
+ for (size_t i = 0; i < ELEMENTSOF(stub_flags); i++)
+ print_yes_no_line(i == 0, FLAGS_SET(stub_features, stub_flags[i].flag), stub_flags[i].name);
+ }
+ if (!sd_id128_is_null(loader_part_uuid))
+ printf(" ESP: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "\n",
+ SD_ID128_FORMAT_VAL(loader_part_uuid));
+ else
+ printf(" ESP: n/a\n");
+ printf(" File: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), strna(loader_path));
+ printf("\n");
+
+ printf("%sRandom Seed:%s\n", ansi_underline(), ansi_normal());
+ have = access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderSystemToken)), F_OK) >= 0;
+ printf(" System Token: %s\n", have ? "set" : "not set");
+
+ if (arg_esp_path) {
+ _cleanup_free_ char *p = NULL;
+
+ p = path_join(arg_esp_path, "/loader/random-seed");
+ if (!p)
+ return log_oom();
+
+ have = access(p, F_OK) >= 0;
+ printf(" Exists: %s\n", yes_no(have));
+ }
+
+ printf("\n");
+ } else
+ printf("%sSystem:%s\n"
+ "Not booted with EFI\n\n",
+ ansi_underline(), ansi_normal());
+
+ if (arg_esp_path) {
+ k = status_binaries(arg_esp_path, esp_uuid);
+ if (k < 0)
+ r = k;
+ }
+
+ if (!arg_root && is_efi_boot()) {
+ k = status_variables();
+ if (k < 0)
+ r = k;
+ }
+
+ if (arg_esp_path || arg_xbootldr_path) {
+ _cleanup_(boot_config_free) BootConfig config = BOOT_CONFIG_NULL;
+
+ k = boot_config_load_and_select(&config,
+ arg_esp_path, esp_devid,
+ arg_xbootldr_path, xbootldr_devid);
+ if (k < 0)
+ r = k;
+ else {
+ k = status_entries(&config,
+ arg_esp_path, esp_uuid,
+ arg_xbootldr_path, xbootldr_uuid);
+ if (k < 0)
+ r = k;
+ }
+ }
+
+ return r;
+}
+
+int verb_list(int argc, char *argv[], void *userdata) {
+ _cleanup_(boot_config_free) BootConfig config = BOOT_CONFIG_NULL;
+ dev_t esp_devid = 0, xbootldr_devid = 0;
+ int r;
+
+ /* If we lack privileges we invoke find_esp_and_warn() in "unprivileged mode" here, which does two
+ * things: turn off logging about access errors and turn off potentially privileged device probing.
+ * Here we're interested in the latter but not the former, hence request the mode, and log about
+ * EACCES. */
+
+ r = acquire_esp(/* unprivileged_mode= */ geteuid() != 0, /* graceful= */ false, NULL, NULL, NULL, NULL, &esp_devid);
+ if (r == -EACCES) /* We really need the ESP path for this call, hence also log about access errors */
+ return log_error_errno(r, "Failed to determine ESP location: %m");
+ if (r < 0)
+ return r;
+
+ r = acquire_xbootldr(/* unprivileged_mode= */ geteuid() != 0, NULL, &xbootldr_devid);
+ if (r == -EACCES)
+ return log_error_errno(r, "Failed to determine XBOOTLDR partition: %m");
+ if (r < 0)
+ return r;
+
+ r = boot_config_load_and_select(&config, arg_esp_path, esp_devid, arg_xbootldr_path, xbootldr_devid);
+ if (r < 0)
+ return r;
+
+ if (config.n_entries == 0 && FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) {
+ log_info("No boot loader entries found.");
+ return 0;
+ }
+
+ pager_open(arg_pager_flags);
+ return show_boot_entries(&config, arg_json_format_flags);
+}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+int verb_status(int argc, char *argv[], void *userdata);
+int verb_list(int argc, char *argv[], void *userdata);
/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#include <sys/mman.h>
+
#include "bootctl.h"
#include "bootctl-util.h"
+#include "fileio.h"
+#include "stat-util.h"
#include "sync-util.h"
int sync_everything(void) {
return ret;
}
+
+const char *get_efi_arch(void) {
+ /* Detect EFI firmware architecture of the running system. On mixed mode systems, it could be 32bit
+ * while the kernel is running in 64bit. */
+
+#ifdef __x86_64__
+ _cleanup_free_ char *platform_size = NULL;
+ int r;
+
+ r = read_one_line_file("/sys/firmware/efi/fw_platform_size", &platform_size);
+ if (r == -ENOENT)
+ return EFI_MACHINE_TYPE_NAME;
+ if (r < 0) {
+ log_warning_errno(r, "Error reading EFI firmware word size, assuming '%i': %m", __WORDSIZE);
+ return EFI_MACHINE_TYPE_NAME;
+ }
+
+ if (streq(platform_size, "64"))
+ return EFI_MACHINE_TYPE_NAME;
+ if (streq(platform_size, "32"))
+ return "ia32";
+
+ log_warning(
+ "Unknown EFI firmware word size '%s', using default word size '%i' instead.",
+ platform_size,
+ __WORDSIZE);
+#endif
+
+ return EFI_MACHINE_TYPE_NAME;
+}
+
+/* search for "#### LoaderInfo: systemd-boot 218 ####" string inside the binary */
+int get_file_version(int fd, char **ret) {
+ struct stat st;
+ char *buf;
+ const char *s, *e;
+ char *x = NULL;
+ int r;
+
+ assert(fd >= 0);
+ assert(ret);
+
+ if (fstat(fd, &st) < 0)
+ return log_error_errno(errno, "Failed to stat EFI binary: %m");
+
+ r = stat_verify_regular(&st);
+ if (r < 0)
+ return log_error_errno(r, "EFI binary is not a regular file: %m");
+
+ if (st.st_size < 27 || file_offset_beyond_memory_size(st.st_size)) {
+ *ret = NULL;
+ return 0;
+ }
+
+ buf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (buf == MAP_FAILED)
+ return log_error_errno(errno, "Failed to memory map EFI binary: %m");
+
+ s = mempmem_safe(buf, st.st_size - 8, "#### LoaderInfo: ", 17);
+ if (!s) {
+ r = -ESRCH;
+ goto finish;
+ }
+
+ e = memmem_safe(s, st.st_size - (s - buf), " ####", 5);
+ if (!e || e - s < 3) {
+ r = log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Malformed version string.");
+ goto finish;
+ }
+
+ x = strndup(s, e - s);
+ if (!x) {
+ r = log_oom();
+ goto finish;
+ }
+ r = 1;
+
+finish:
+ (void) munmap(buf, st.st_size);
+ if (r >= 0)
+ *ret = x;
+
+ return r;
+}
#pragma once
int sync_everything(void);
+
+const char *get_efi_arch(void);
+
+int get_file_version(int fd, char **ret);
#include "bootctl.h"
#include "bootctl-random-seed.h"
#include "bootctl-reboot-to-firmware.h"
-#include "bootctl-systemd-efi-options.h"
#include "bootctl-set-efivar.h"
+#include "bootctl-status.h"
+#include "bootctl-systemd-efi-options.h"
#include "bootctl-util.h"
#include "bootspec.h"
#include "build.h"
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
STATIC_DESTRUCTOR_REGISTER(arg_efi_boot_option_description, freep);
-static const char *arg_dollar_boot_path(void) {
- /* $BOOT shall be the XBOOTLDR partition if it exists, and otherwise the ESP */
- return arg_xbootldr_path ?: arg_esp_path;
-}
-
static const char *pick_efi_boot_option_description(void) {
return arg_efi_boot_option_description ?: "Linux Boot Manager";
}
-static int acquire_esp(
+int acquire_esp(
bool unprivileged_mode,
bool graceful,
uint32_t *ret_part,
return 0;
}
-static int acquire_xbootldr(
+int acquire_xbootldr(
bool unprivileged_mode,
sd_id128_t *ret_uuid,
dev_t *ret_devid) {
return 0;
}
-/* search for "#### LoaderInfo: systemd-boot 218 ####" string inside the binary */
-static int get_file_version(int fd, char **v) {
- struct stat st;
- char *buf;
- const char *s, *e;
- char *x = NULL;
- int r;
-
- assert(fd >= 0);
- assert(v);
-
- if (fstat(fd, &st) < 0)
- return log_error_errno(errno, "Failed to stat EFI binary: %m");
-
- r = stat_verify_regular(&st);
- if (r < 0)
- return log_error_errno(r, "EFI binary is not a regular file: %m");
-
- if (st.st_size < 27 || file_offset_beyond_memory_size(st.st_size)) {
- *v = NULL;
- return 0;
- }
-
- buf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
- if (buf == MAP_FAILED)
- return log_error_errno(errno, "Failed to memory map EFI binary: %m");
-
- s = mempmem_safe(buf, st.st_size - 8, "#### LoaderInfo: ", 17);
- if (!s)
- goto finish;
-
- e = memmem_safe(s, st.st_size - (s - buf), " ####", 5);
- if (!e || e - s < 3) {
- r = log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Malformed version string.");
- goto finish;
- }
-
- x = strndup(s, e - s);
- if (!x) {
- r = log_oom();
- goto finish;
- }
- r = 1;
-
-finish:
- (void) munmap(buf, st.st_size);
- *v = x;
- return r;
-}
-
-static const char *get_efi_arch(void) {
- /* Detect EFI firmware architecture of the running system. On mixed mode systems, it could be 32bit
- * while the kernel is running in 64bit. */
-
-#ifdef __x86_64__
- _cleanup_free_ char *platform_size = NULL;
- int r;
-
- r = read_one_line_file("/sys/firmware/efi/fw_platform_size", &platform_size);
- if (r == -ENOENT)
- return EFI_MACHINE_TYPE_NAME;
- if (r < 0) {
- log_warning_errno(r, "Error reading EFI firmware word size, assuming '%i': %m", __WORDSIZE);
- return EFI_MACHINE_TYPE_NAME;
- }
-
- if (streq(platform_size, "64"))
- return EFI_MACHINE_TYPE_NAME;
- if (streq(platform_size, "32"))
- return "ia32";
-
- log_warning(
- "Unknown EFI firmware word size '%s', using default word size '%i' instead.",
- platform_size,
- __WORDSIZE);
-#endif
-
- return EFI_MACHINE_TYPE_NAME;
-}
-
-static int enumerate_binaries(
- const char *esp_path,
- const char *path,
- const char *prefix,
- char **previous,
- bool *is_first) {
-
- _cleanup_closedir_ DIR *d = NULL;
- _cleanup_free_ char *p = NULL;
- int c = 0, r;
-
- assert(esp_path);
- assert(path);
- assert(previous);
- assert(is_first);
-
- r = chase_symlinks_and_opendir(path, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &p, &d);
- if (r == -ENOENT)
- return 0;
- if (r < 0)
- return log_error_errno(r, "Failed to read \"%s/%s\": %m", esp_path, path);
-
- FOREACH_DIRENT(de, d, break) {
- _cleanup_free_ char *v = NULL;
- _cleanup_close_ int fd = -1;
-
- if (!endswith_no_case(de->d_name, ".efi"))
- continue;
-
- if (prefix && !startswith_no_case(de->d_name, prefix))
- continue;
-
- fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC);
- if (fd < 0)
- return log_error_errno(errno, "Failed to open \"%s/%s\" for reading: %m", p, de->d_name);
-
- r = get_file_version(fd, &v);
- if (r < 0)
- return r;
-
- if (*previous) { /* let's output the previous entry now, since now we know that there will be one more, and can draw the tree glyph properly */
- printf(" %s %s%s\n",
- *is_first ? "File:" : " ",
- special_glyph(SPECIAL_GLYPH_TREE_BRANCH), *previous);
- *is_first = false;
- *previous = mfree(*previous);
- }
-
- /* Do not output this entry immediately, but store what should be printed in a state
- * variable, because we only will know the tree glyph to print (branch or final edge) once we
- * read one more entry */
- if (r > 0)
- r = asprintf(previous, "/%s/%s (%s%s%s)", path, de->d_name, ansi_highlight(), v, ansi_normal());
- else
- r = asprintf(previous, "/%s/%s", path, de->d_name);
- if (r < 0)
- return log_oom();
-
- c++;
- }
-
- return c;
-}
-
-static int status_binaries(const char *esp_path, sd_id128_t partition) {
- _cleanup_free_ char *last = NULL;
- bool is_first = true;
- int r, k;
-
- printf("%sAvailable Boot Loaders on ESP:%s\n", ansi_underline(), ansi_normal());
-
- if (!esp_path) {
- printf(" ESP: Cannot find or access mount point of ESP.\n\n");
- return -ENOENT;
- }
-
- printf(" ESP: %s", esp_path);
- if (!sd_id128_is_null(partition))
- printf(" (/dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR ")", SD_ID128_FORMAT_VAL(partition));
- printf("\n");
-
- r = enumerate_binaries(esp_path, "EFI/systemd", NULL, &last, &is_first);
- if (r < 0) {
- printf("\n");
- return r;
- }
-
- k = enumerate_binaries(esp_path, "EFI/BOOT", "boot", &last, &is_first);
- if (k < 0) {
- printf("\n");
- return k;
- }
-
- if (last) /* let's output the last entry now, since now we know that there will be no more, and can draw the tree glyph properly */
- printf(" %s %s%s\n",
- is_first ? "File:" : " ",
- special_glyph(SPECIAL_GLYPH_TREE_RIGHT), last);
-
- if (r == 0 && !arg_quiet)
- log_info("systemd-boot not installed in ESP.");
- if (k == 0 && !arg_quiet)
- log_info("No default/fallback boot loader installed in ESP.");
-
- printf("\n");
- return 0;
-}
-
-static int print_efi_option(uint16_t id, int *n_printed, bool in_order) {
- _cleanup_free_ char *title = NULL;
- _cleanup_free_ char *path = NULL;
- sd_id128_t partition;
- bool active;
- int r;
-
- assert(n_printed);
-
- r = efi_get_boot_option(id, &title, &partition, &path, &active);
- if (r == -ENOENT) {
- log_debug_errno(r, "Boot option 0x%04X referenced but missing, ignoring: %m", id);
- return 0;
- }
- if (r < 0)
- return log_error_errno(r, "Failed to read boot option 0x%04X: %m", id);
-
- /* print only configured entries with partition information */
- if (!path || sd_id128_is_null(partition)) {
- log_debug("Ignoring boot entry 0x%04X without partition information.", id);
- return 0;
- }
-
- efi_tilt_backslashes(path);
-
- if (*n_printed == 0) /* Print section title before first entry */
- printf("%sBoot Loaders Listed in EFI Variables:%s\n", ansi_underline(), ansi_normal());
-
- printf(" Title: %s%s%s\n", ansi_highlight(), strna(title), ansi_normal());
- printf(" ID: 0x%04X\n", id);
- printf(" Status: %sactive%s\n", active ? "" : "in", in_order ? ", boot-order" : "");
- printf(" Partition: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "\n",
- SD_ID128_FORMAT_VAL(partition));
- printf(" File: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), path);
- printf("\n");
-
- (*n_printed)++;
- return 1;
-}
-
-static int status_variables(void) {
- _cleanup_free_ uint16_t *options = NULL, *order = NULL;
- int n_options, n_order, n_printed = 0;
-
- n_options = efi_get_boot_options(&options);
- if (n_options == -ENOENT)
- return log_error_errno(n_options,
- "Failed to access EFI variables, efivarfs"
- " needs to be available at /sys/firmware/efi/efivars/.");
- if (n_options < 0)
- return log_error_errno(n_options, "Failed to read EFI boot entries: %m");
-
- n_order = efi_get_boot_order(&order);
- if (n_order == -ENOENT)
- n_order = 0;
- else if (n_order < 0)
- return log_error_errno(n_order, "Failed to read EFI boot order: %m");
-
- /* print entries in BootOrder first */
- for (int i = 0; i < n_order; i++)
- (void) print_efi_option(order[i], &n_printed, /* in_order= */ true);
-
- /* print remaining entries */
- for (int i = 0; i < n_options; i++) {
- for (int j = 0; j < n_order; j++)
- if (options[i] == order[j])
- goto next_option;
-
- (void) print_efi_option(options[i], &n_printed, /* in_order= */ false);
-
- next_option:
- continue;
- }
-
- if (n_printed == 0)
- printf("No boot loaders listed in EFI Variables.\n\n");
-
- return 0;
-}
-
-static int boot_config_load_and_select(
- BootConfig *config,
- const char *esp_path,
- dev_t esp_devid,
- const char *xbootldr_path,
- dev_t xbootldr_devid) {
-
- int r;
-
- /* If XBOOTLDR and ESP actually refer to the same block device, suppress XBOOTLDR, since it would
- * find the same entries twice. */
- bool same = esp_path && xbootldr_path && devnum_set_and_equal(esp_devid, xbootldr_devid);
-
- r = boot_config_load(config, esp_path, same ? NULL : xbootldr_path);
- if (r < 0)
- return r;
-
- if (!arg_root) {
- _cleanup_strv_free_ char **efi_entries = NULL;
-
- r = efi_loader_get_entries(&efi_entries);
- if (r == -ENOENT || ERRNO_IS_NOT_SUPPORTED(r))
- log_debug_errno(r, "Boot loader reported no entries.");
- else if (r < 0)
- log_warning_errno(r, "Failed to determine entries reported by boot loader, ignoring: %m");
- else
- (void) boot_config_augment_from_loader(config, efi_entries, /* only_auto= */ false);
- }
-
- return boot_config_select_special_entries(config, /* skip_efivars= */ !!arg_root);
-}
-
-static int status_entries(
- const BootConfig *config,
- const char *esp_path,
- sd_id128_t esp_partition_uuid,
- const char *xbootldr_path,
- sd_id128_t xbootldr_partition_uuid) {
-
- sd_id128_t dollar_boot_partition_uuid;
- const char *dollar_boot_path;
- int r;
-
- assert(config);
- assert(esp_path || xbootldr_path);
-
- if (xbootldr_path) {
- dollar_boot_path = xbootldr_path;
- dollar_boot_partition_uuid = xbootldr_partition_uuid;
- } else {
- dollar_boot_path = esp_path;
- dollar_boot_partition_uuid = esp_partition_uuid;
- }
-
- printf("%sBoot Loader Entries:%s\n"
- " $BOOT: %s", ansi_underline(), ansi_normal(), dollar_boot_path);
- if (!sd_id128_is_null(dollar_boot_partition_uuid))
- printf(" (/dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR ")",
- SD_ID128_FORMAT_VAL(dollar_boot_partition_uuid));
- printf("\n\n");
-
- if (config->default_entry < 0)
- printf("%zu entries, no entry could be determined as default.\n", config->n_entries);
- else {
- printf("%sDefault Boot Loader Entry:%s\n", ansi_underline(), ansi_normal());
-
- r = show_boot_entry(
- boot_config_default_entry(config),
- /* show_as_default= */ false,
- /* show_as_selected= */ false,
- /* show_discovered= */ false);
- if (r > 0)
- /* < 0 is already logged by the function itself, let's just emit an extra warning if
- the default entry is broken */
- printf("\nWARNING: default boot entry is broken\n");
- }
-
- return 0;
-}
-
static int compare_product(const char *a, const char *b) {
size_t x, y;
return 1;
}
-static void read_efi_var(const char *variable, char **ret) {
- int r;
-
- r = efi_get_variable_string(variable, ret);
- if (r < 0 && r != -ENOENT)
- log_warning_errno(r, "Failed to read EFI variable %s: %m", variable);
-}
-
-static void print_yes_no_line(bool first, bool good, const char *name) {
- printf("%s%s %s\n",
- first ? " Features: " : " ",
- COLOR_MARK_BOOL(good),
- name);
-}
-
static int are_we_installed(const char *esp_path) {
int r;
return r == 0;
}
-static int verb_status(int argc, char *argv[], void *userdata) {
- sd_id128_t esp_uuid = SD_ID128_NULL, xbootldr_uuid = SD_ID128_NULL;
- dev_t esp_devid = 0, xbootldr_devid = 0;
- int r, k;
-
- r = acquire_esp(/* unprivileged_mode= */ geteuid() != 0, /* graceful= */ false, NULL, NULL, NULL, &esp_uuid, &esp_devid);
- if (arg_print_esp_path) {
- if (r == -EACCES) /* If we couldn't acquire the ESP path, log about access errors (which is the only
- * error the find_esp_and_warn() won't log on its own) */
- return log_error_errno(r, "Failed to determine ESP location: %m");
- if (r < 0)
- return r;
-
- puts(arg_esp_path);
- }
-
- r = acquire_xbootldr(/* unprivileged_mode= */ geteuid() != 0, &xbootldr_uuid, &xbootldr_devid);
- if (arg_print_dollar_boot_path) {
- if (r == -EACCES)
- return log_error_errno(r, "Failed to determine XBOOTLDR partition: %m");
- if (r < 0)
- return r;
-
- const char *path = arg_dollar_boot_path();
- if (!path)
- return log_error_errno(SYNTHETIC_ERRNO(EACCES), "Failed to determine XBOOTLDR location: %m");
-
- puts(path);
- }
-
- if (arg_print_esp_path || arg_print_dollar_boot_path)
- return 0;
-
- r = 0; /* If we couldn't determine the path, then don't consider that a problem from here on, just
- * show what we can show */
-
- pager_open(arg_pager_flags);
-
- if (!arg_root && is_efi_boot()) {
- static const struct {
- uint64_t flag;
- const char *name;
- } loader_flags[] = {
- { EFI_LOADER_FEATURE_BOOT_COUNTING, "Boot counting" },
- { EFI_LOADER_FEATURE_CONFIG_TIMEOUT, "Menu timeout control" },
- { EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT, "One-shot menu timeout control" },
- { EFI_LOADER_FEATURE_ENTRY_DEFAULT, "Default entry control" },
- { EFI_LOADER_FEATURE_ENTRY_ONESHOT, "One-shot entry control" },
- { EFI_LOADER_FEATURE_XBOOTLDR, "Support for XBOOTLDR partition" },
- { EFI_LOADER_FEATURE_RANDOM_SEED, "Support for passing random seed to OS" },
- { EFI_LOADER_FEATURE_LOAD_DRIVER, "Load drop-in drivers" },
- { EFI_LOADER_FEATURE_SORT_KEY, "Support Type #1 sort-key field" },
- { EFI_LOADER_FEATURE_SAVED_ENTRY, "Support @saved pseudo-entry" },
- { EFI_LOADER_FEATURE_DEVICETREE, "Support Type #1 devicetree field" },
- };
- static const struct {
- uint64_t flag;
- const char *name;
- } stub_flags[] = {
- { EFI_STUB_FEATURE_REPORT_BOOT_PARTITION, "Stub sets ESP information" },
- { EFI_STUB_FEATURE_PICK_UP_CREDENTIALS, "Picks up credentials from boot partition" },
- { EFI_STUB_FEATURE_PICK_UP_SYSEXTS, "Picks up system extension images from boot partition" },
- { EFI_STUB_FEATURE_THREE_PCRS, "Measures kernel+command line+sysexts" },
- { EFI_STUB_FEATURE_RANDOM_SEED, "Support for passing random seed to OS" },
- };
- _cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL;
- sd_id128_t loader_part_uuid = SD_ID128_NULL;
- uint64_t loader_features = 0, stub_features = 0;
- Tpm2Support s;
- int have;
-
- read_efi_var(EFI_LOADER_VARIABLE(LoaderFirmwareType), &fw_type);
- read_efi_var(EFI_LOADER_VARIABLE(LoaderFirmwareInfo), &fw_info);
- read_efi_var(EFI_LOADER_VARIABLE(LoaderInfo), &loader);
- read_efi_var(EFI_LOADER_VARIABLE(StubInfo), &stub);
- read_efi_var(EFI_LOADER_VARIABLE(LoaderImageIdentifier), &loader_path);
- (void) efi_loader_get_features(&loader_features);
- (void) efi_stub_get_features(&stub_features);
-
- if (loader_path)
- efi_tilt_backslashes(loader_path);
-
- k = efi_loader_get_device_part_uuid(&loader_part_uuid);
- if (k < 0 && k != -ENOENT)
- r = log_warning_errno(k, "Failed to read EFI variable LoaderDevicePartUUID: %m");
-
- SecureBootMode secure = efi_get_secure_boot_mode();
- printf("%sSystem:%s\n", ansi_underline(), ansi_normal());
- printf(" Firmware: %s%s (%s)%s\n", ansi_highlight(), strna(fw_type), strna(fw_info), ansi_normal());
- printf(" Firmware Arch: %s\n", get_efi_arch());
- printf(" Secure Boot: %sd (%s)\n",
- enable_disable(IN_SET(secure, SECURE_BOOT_USER, SECURE_BOOT_DEPLOYED)),
- secure_boot_mode_to_string(secure));
-
- s = tpm2_support();
- printf(" TPM2 Support: %s%s%s\n",
- FLAGS_SET(s, TPM2_SUPPORT_FIRMWARE|TPM2_SUPPORT_DRIVER) ? ansi_highlight_green() :
- (s & (TPM2_SUPPORT_FIRMWARE|TPM2_SUPPORT_DRIVER)) != 0 ? ansi_highlight_red() : ansi_highlight_yellow(),
- FLAGS_SET(s, TPM2_SUPPORT_FIRMWARE|TPM2_SUPPORT_DRIVER) ? "yes" :
- (s & TPM2_SUPPORT_FIRMWARE) ? "firmware only, driver unavailable" :
- (s & TPM2_SUPPORT_DRIVER) ? "driver only, firmware unavailable" : "no",
- ansi_normal());
-
- k = efi_get_reboot_to_firmware();
- if (k > 0)
- printf(" Boot into FW: %sactive%s\n", ansi_highlight_yellow(), ansi_normal());
- else if (k == 0)
- printf(" Boot into FW: supported\n");
- else if (k == -EOPNOTSUPP)
- printf(" Boot into FW: not supported\n");
- else {
- errno = -k;
- printf(" Boot into FW: %sfailed%s (%m)\n", ansi_highlight_red(), ansi_normal());
- }
- printf("\n");
-
- printf("%sCurrent Boot Loader:%s\n", ansi_underline(), ansi_normal());
- printf(" Product: %s%s%s\n", ansi_highlight(), strna(loader), ansi_normal());
-
- for (size_t i = 0; i < ELEMENTSOF(loader_flags); i++)
- print_yes_no_line(i == 0, FLAGS_SET(loader_features, loader_flags[i].flag), loader_flags[i].name);
-
- sd_id128_t bootloader_esp_uuid;
- bool have_bootloader_esp_uuid = efi_loader_get_device_part_uuid(&bootloader_esp_uuid) >= 0;
-
- print_yes_no_line(false, have_bootloader_esp_uuid, "Boot loader sets ESP information");
- if (have_bootloader_esp_uuid && !sd_id128_is_null(esp_uuid) &&
- !sd_id128_equal(esp_uuid, bootloader_esp_uuid))
- printf("WARNING: The boot loader reports a different ESP UUID than detected ("SD_ID128_UUID_FORMAT_STR" vs. "SD_ID128_UUID_FORMAT_STR")!\n",
- SD_ID128_FORMAT_VAL(bootloader_esp_uuid),
- SD_ID128_FORMAT_VAL(esp_uuid));
-
- if (stub) {
- printf(" Stub: %s\n", stub);
- for (size_t i = 0; i < ELEMENTSOF(stub_flags); i++)
- print_yes_no_line(i == 0, FLAGS_SET(stub_features, stub_flags[i].flag), stub_flags[i].name);
- }
- if (!sd_id128_is_null(loader_part_uuid))
- printf(" ESP: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "\n",
- SD_ID128_FORMAT_VAL(loader_part_uuid));
- else
- printf(" ESP: n/a\n");
- printf(" File: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), strna(loader_path));
- printf("\n");
-
- printf("%sRandom Seed:%s\n", ansi_underline(), ansi_normal());
- have = access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderSystemToken)), F_OK) >= 0;
- printf(" System Token: %s\n", have ? "set" : "not set");
-
- if (arg_esp_path) {
- _cleanup_free_ char *p = NULL;
-
- p = path_join(arg_esp_path, "/loader/random-seed");
- if (!p)
- return log_oom();
-
- have = access(p, F_OK) >= 0;
- printf(" Exists: %s\n", yes_no(have));
- }
-
- printf("\n");
- } else
- printf("%sSystem:%s\n"
- "Not booted with EFI\n\n",
- ansi_underline(), ansi_normal());
-
- if (arg_esp_path) {
- k = status_binaries(arg_esp_path, esp_uuid);
- if (k < 0)
- r = k;
- }
-
- if (!arg_root && is_efi_boot()) {
- k = status_variables();
- if (k < 0)
- r = k;
- }
-
- if (arg_esp_path || arg_xbootldr_path) {
- _cleanup_(boot_config_free) BootConfig config = BOOT_CONFIG_NULL;
-
- k = boot_config_load_and_select(&config,
- arg_esp_path, esp_devid,
- arg_xbootldr_path, xbootldr_devid);
- if (k < 0)
- r = k;
- else {
- k = status_entries(&config,
- arg_esp_path, esp_uuid,
- arg_xbootldr_path, xbootldr_uuid);
- if (k < 0)
- r = k;
- }
- }
-
- return r;
-}
-
-static int verb_list(int argc, char *argv[], void *userdata) {
- _cleanup_(boot_config_free) BootConfig config = BOOT_CONFIG_NULL;
- dev_t esp_devid = 0, xbootldr_devid = 0;
- int r;
-
- /* If we lack privileges we invoke find_esp_and_warn() in "unprivileged mode" here, which does two
- * things: turn off logging about access errors and turn off potentially privileged device probing.
- * Here we're interested in the latter but not the former, hence request the mode, and log about
- * EACCES. */
-
- r = acquire_esp(/* unprivileged_mode= */ geteuid() != 0, /* graceful= */ false, NULL, NULL, NULL, NULL, &esp_devid);
- if (r == -EACCES) /* We really need the ESP path for this call, hence also log about access errors */
- return log_error_errno(r, "Failed to determine ESP location: %m");
- if (r < 0)
- return r;
-
- r = acquire_xbootldr(/* unprivileged_mode= */ geteuid() != 0, NULL, &xbootldr_devid);
- if (r == -EACCES)
- return log_error_errno(r, "Failed to determine XBOOTLDR partition: %m");
- if (r < 0)
- return r;
-
- r = boot_config_load_and_select(&config, arg_esp_path, esp_devid, arg_xbootldr_path, xbootldr_devid);
- if (r < 0)
- return r;
-
- if (config.n_entries == 0 && FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) {
- log_info("No boot loader entries found.");
- return 0;
- }
-
- pager_open(arg_pager_flags);
- return show_boot_entries(&config, arg_json_format_flags);
-}
-
static int verb_install(int argc, char *argv[], void *userdata) {
sd_id128_t uuid = SD_ID128_NULL;
uint64_t pstart = 0, psize = 0;
extern char *arg_root;
extern char *arg_image;
extern char *arg_efi_boot_option_description;
+
+static inline const char *arg_dollar_boot_path(void) {
+ /* $BOOT shall be the XBOOTLDR partition if it exists, and otherwise the ESP */
+ return arg_xbootldr_path ?: arg_esp_path;
+}
+
+int acquire_esp(bool unprivileged_mode, bool graceful, uint32_t *ret_part, uint64_t *ret_pstart, uint64_t *ret_psize, sd_id128_t *ret_uuid, dev_t *ret_devid);
+int acquire_xbootldr(bool unprivileged_mode, sd_id128_t *ret_uuid, dev_t *ret_devid);