]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/boot/bootctl.c
Merge pull request #24054 from keszybz/initrd-no-reload
[thirdparty/systemd.git] / src / boot / bootctl.c
index 4907b3ce3deba1bf378087aa77b84524c36f0a77..10da1c8d7f2973bae0de00fd60d4f7157c4e31e5 100644 (file)
@@ -456,13 +456,21 @@ static const char *get_efi_arch(void) {
         return EFI_MACHINE_TYPE_NAME;
 }
 
-static int enumerate_binaries(const char *esp_path, const char *path, const char *prefix) {
+static int enumerate_binaries(
+                const char *esp_path,
+                const char *path,
+                const char *prefix,
+                char **previous,
+                bool *is_first) {
+
         _cleanup_closedir_ DIR *d = NULL;
         const char *p;
         int c = 0, r;
 
         assert(esp_path);
         assert(path);
+        assert(previous);
+        assert(is_first);
 
         p = prefix_roota(esp_path, path);
         d = opendir(p);
@@ -490,10 +498,24 @@ static int enumerate_binaries(const char *esp_path, const char *path, const char
                 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)
-                        printf("         File: %s/%s/%s (%s%s%s)\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), path, de->d_name, ansi_highlight(), v, ansi_normal());
+                        r = asprintf(previous, "/%s/%s (%s%s%s)", path, de->d_name, ansi_highlight(), v, ansi_normal());
                 else
-                        printf("         File: %s/%s/%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), path, de->d_name);
+                        r = asprintf(previous, "/%s/%s", path, de->d_name);
+                if (r < 0)
+                        return log_oom();
 
                 c++;
         }
@@ -502,9 +524,11 @@ static int enumerate_binaries(const char *esp_path, const char *path, const char
 }
 
 static int status_binaries(const char *esp_path, sd_id128_t partition) {
-        int r;
+        _cleanup_free_ char *last = NULL;
+        bool is_first = true;
+        int r, k;
 
-        printf("Available Boot Loaders on ESP:\n");
+        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");
@@ -516,42 +540,56 @@ static int status_binaries(const char *esp_path, sd_id128_t 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);
-        if (r < 0)
-                goto finish;
-        if (r == 0 && !arg_quiet)
-                log_info("systemd-boot not installed in ESP.");
+        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);
 
-        r = enumerate_binaries(esp_path, "EFI/BOOT", "boot");
-        if (r < 0)
-                goto finish;
         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.");
 
-        r = 0;
-
-finish:
         printf("\n");
-        return r;
+        return 0;
 }
 
-static int print_efi_option(uint16_t id, bool in_order) {
+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 < 0)
-                return r;
+                return log_error_errno(r, "Failed to read boot option %u: %m", id);
 
         /* print only configured entries with partition information */
-        if (!path || sd_id128_is_null(partition))
+        if (!path || sd_id128_is_null(partition)) {
+                log_debug("Ignoring boot entry %u 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" : "");
@@ -560,12 +598,13 @@ static int print_efi_option(uint16_t id, bool in_order) {
         printf("         File: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), path);
         printf("\n");
 
-        return 0;
+        (*n_printed)++;
+        return 1;
 }
 
 static int status_variables(void) {
         _cleanup_free_ uint16_t *options = NULL, *order = NULL;
-        int n_options, n_order;
+        int n_options, n_order, n_printed = 0;
 
         n_options = efi_get_boot_options(&options);
         if (n_options == -ENOENT)
@@ -582,9 +621,8 @@ static int status_variables(void) {
                 return log_error_errno(n_order, "Failed to read EFI boot order: %m");
 
         /* print entries in BootOrder first */
-        printf("Boot Loaders Listed in EFI Variables:\n");
         for (int i = 0; i < n_order; i++)
-                print_efi_option(order[i], true);
+                (void) print_efi_option(order[i], &n_printed, /* in_order= */ true);
 
         /* print remaining entries */
         for (int i = 0; i < n_options; i++) {
@@ -592,12 +630,15 @@ static int status_variables(void) {
                         if (options[i] == order[j])
                                 goto next_option;
 
-                print_efi_option(options[i], false);
+                (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;
 }
 
@@ -655,8 +696,8 @@ static int status_entries(
                 dollar_boot_partition_uuid = esp_partition_uuid;
         }
 
-        printf("Boot Loader Entries:\n"
-               "        $BOOT: %s", dollar_boot_path);
+        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));
@@ -665,7 +706,7 @@ static int status_entries(
         if (config->default_entry < 0)
                 printf("%zu entries, no entry could be determined as default.\n", config->n_entries);
         else {
-                printf("Default Boot Loader Entry:\n");
+                printf("%sDefault Boot Loader Entry:%s\n", ansi_underline(), ansi_normal());
 
                 r = show_boot_entry(
                                 boot_config_default_entry(config),
@@ -872,7 +913,7 @@ static int copy_one_file(const char *esp_path, const char *name, bool force) {
                                        "Failed to resolve path %s%s%s: %m",
                                        p,
                                        root ? " under directory " : "",
-                                       root ?: "");
+                                       strempty(root));
 
         q = path_join("/EFI/systemd/", dest_name);
         if (!q)
@@ -918,7 +959,7 @@ static int install_binaries(const char *esp_path, const char *arch, bool force)
         if (r == -ENOENT && root && arg_install_source == ARG_INSTALL_SOURCE_AUTO)
                 r = chase_symlinks_and_opendir(BOOTLIBDIR, NULL, CHASE_PREFIX_ROOT, &path, &d);
         if (r < 0)
-                return log_error_errno(r, "Failed to open boot loader directory %s%s: %m", root ?: "", BOOTLIBDIR);
+                return log_error_errno(r, "Failed to open boot loader directory %s%s: %m", strempty(root), BOOTLIBDIR);
 
         const char *suffix = strjoina(arch, ".efi");
         const char *suffix_signed = strjoina(arch, ".efi.signed");
@@ -1714,7 +1755,7 @@ static int verb_status(int argc, char *argv[], void *userdata) {
                 static const struct {
                         uint64_t flag;
                         const char *name;
-                } flags[] = {
+                } 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"         },
@@ -1723,10 +1764,22 @@ static int verb_status(int argc, char *argv[], void *userdata) {
                         { 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"                 },
                 };
                 _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;
+                uint64_t loader_features = 0, stub_features = 0;
                 Tpm2Support s;
                 int have;
 
@@ -1736,6 +1789,7 @@ static int verb_status(int argc, char *argv[], void *userdata) {
                 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);
@@ -1745,7 +1799,7 @@ static int verb_status(int argc, char *argv[], void *userdata) {
                         r = log_warning_errno(k, "Failed to read EFI variable LoaderDevicePartUUID: %m");
 
                 SecureBootMode secure = efi_get_secure_boot_mode();
-                printf("System:\n");
+                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",
@@ -1774,11 +1828,11 @@ static int verb_status(int argc, char *argv[], void *userdata) {
                 }
                 printf("\n");
 
-                printf("Current Boot Loader:\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(flags); i++)
-                        print_yes_no_line(i == 0, FLAGS_SET(loader_features, flags[i].flag), flags[i].name);
+                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;
@@ -1790,8 +1844,11 @@ static int verb_status(int argc, char *argv[], void *userdata) {
                                SD_ID128_FORMAT_VAL(bootloader_esp_uuid),
                                SD_ID128_FORMAT_VAL(esp_uuid));
 
-                if (stub)
+                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));
@@ -1800,7 +1857,7 @@ static int verb_status(int argc, char *argv[], void *userdata) {
                 printf("         File: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), strna(loader_path));
                 printf("\n");
 
-                printf("Random Seed:\n");
+                printf("%sRandom Seed:%s\n", ansi_underline(), ansi_normal());
                 have = access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderRandomSeed)), F_OK) >= 0;
                 printf(" Passed to OS: %s\n", yes_no(have));
                 have = access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderSystemToken)), F_OK) >= 0;
@@ -1819,7 +1876,9 @@ static int verb_status(int argc, char *argv[], void *userdata) {
 
                 printf("\n");
         } else
-                printf("System:\n    Not booted with EFI\n\n");
+                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);