]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
bootctl: split out "status" verb too
authorLennart Poettering <lennart@poettering.net>
Mon, 19 Dec 2022 10:04:17 +0000 (11:04 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 19 Dec 2022 11:08:02 +0000 (12:08 +0100)
meson.build
src/boot/bootctl-status.c [new file with mode: 0644]
src/boot/bootctl-status.h [new file with mode: 0644]
src/boot/bootctl-util.c
src/boot/bootctl-util.h
src/boot/bootctl.c
src/boot/bootctl.h

index 9155ec4f7891889832707bf61ec3e6bdb1275046..23cc99c74faaf72cbe7ef2a5c10fda58660e388f 100644 (file)
@@ -2613,6 +2613,8 @@ if conf.get('HAVE_BLKID') == 1 and conf.get('HAVE_GNU_EFI') == 1
                  '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',
diff --git a/src/boot/bootctl-status.c b/src/boot/bootctl-status.c
new file mode 100644 (file)
index 0000000..44f3800
--- /dev/null
@@ -0,0 +1,537 @@
+/* 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);
+}
diff --git a/src/boot/bootctl-status.h b/src/boot/bootctl-status.h
new file mode 100644 (file)
index 0000000..0b57c86
--- /dev/null
@@ -0,0 +1,4 @@
+/* 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);
index 2d3f7d4537f9612b2a1a90e2f0d2e4fa280b9fd8..c994f5f95240b644fd7b9e7ef8ad5b95a6d43e86 100644 (file)
@@ -1,7 +1,11 @@
 /* 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) {
@@ -21,3 +25,87 @@ 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;
+}
index 3cac37b7a5cbb71644e1dc14484b35edcdefa6a3..baa9c5711af505dcfae8ddb4c25876a5d59f99c3 100644 (file)
@@ -2,3 +2,7 @@
 #pragma once
 
 int sync_everything(void);
+
+const char *get_efi_arch(void);
+
+int get_file_version(int fd, char **ret);
index f1e05067073c8d2e955dc5ffea64db189975a10a..c8b1ce50dee9cf9473f2cc0a28db7bb16ce2eac5 100644 (file)
@@ -17,8 +17,9 @@
 #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"
@@ -107,16 +108,11 @@ STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
 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,
@@ -153,7 +149,7 @@ static int acquire_esp(
         return 0;
 }
 
-static int acquire_xbootldr(
+int acquire_xbootldr(
                 bool unprivileged_mode,
                 sd_id128_t *ret_uuid,
                 dev_t *ret_devid) {
@@ -394,353 +390,6 @@ static int settle_make_entry_directory(void) {
         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;
 
@@ -1707,21 +1356,6 @@ static int parse_argv(int argc, char *argv[]) {
         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;
 
@@ -1751,239 +1385,6 @@ static int are_we_installed(const char *esp_path) {
         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;
index 955f11209c3614815454888097e6c5f4ad9a44ce..baf0d3ef50c3775291b7d22dacae3ae0c419c20b 100644 (file)
@@ -23,3 +23,11 @@ extern bool arg_arch_all;
 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);