Let's improve display of boot entries and show what type they have (i.e.
boot loader spec type 1, or type 2, or auto-discovered or reported by
boot loader), and in particular mark entries the boot loader discovered
but we can't find (i.e. that likely vanished, or possibly couldn't be
found due to a misconfiguration) and that the boot loader didn't find
but we see (which are new, or possibly also the result of
misconfiguraiton).
This is supposed to be a replacement for #22161, but instead of hiding
vanished entries, highlights them, which I think is more appropriate for
a low-level tool such bootctl.
Replaces: #22161 #22398
#include "rm-rf.h"
#include "stat-util.h"
#include "stdio-util.h"
+#include "string-table.h"
#include "string-util.h"
#include "strv.h"
#include "sync-util.h"
*ret_status = status;
}
+static const char* const boot_entry_type_table[_BOOT_ENTRY_TYPE_MAX] = {
+ [BOOT_ENTRY_CONF] = "Boot Loader Specification Type #1 (.conf)",
+ [BOOT_ENTRY_UNIFIED] = "Boot Loader Specification Type #2 (.efi)",
+ [BOOT_ENTRY_LOADER] = "Reported by Boot Loader",
+ [BOOT_ENTRY_LOADER_AUTO] = "Automatic",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(boot_entry_type, BootEntryType);
+
static int boot_entry_show(
const BootEntry *e,
bool show_as_default,
- bool show_as_selected) {
+ bool show_as_selected,
+ bool show_reported) {
int status = 0;
assert(e);
- printf(" title: %s%s%s" "%s%s%s" "%s%s%s\n",
- ansi_highlight(), boot_entry_title(e), ansi_normal(),
- ansi_highlight_green(), show_as_default ? " (default)" : "", ansi_normal(),
- ansi_highlight_magenta(), show_as_selected ? " (selected)" : "", ansi_normal());
+ printf(" type: %s\n",
+ boot_entry_type_to_string(e->type));
+
+ printf(" title: %s%s%s",
+ ansi_highlight(), boot_entry_title(e), ansi_normal());
+
+ if (show_as_default)
+ printf(" %s(default)%s",
+ ansi_highlight_green(), ansi_normal());
+
+ if (show_as_selected)
+ printf(" %s(selected)%s",
+ ansi_highlight_magenta(), ansi_normal());
+
+ if (show_reported) {
+ if (e->type == BOOT_ENTRY_LOADER)
+ printf(" %s(reported/absent)%s",
+ ansi_highlight_red(), ansi_normal());
+ else if (!e->reported_by_loader && e->type != BOOT_ENTRY_LOADER_AUTO)
+ printf(" %s(not reported/new)%s",
+ ansi_highlight_green(), ansi_normal());
+ }
+
+ putchar('\n');
if (e->id)
printf(" id: %s\n", e->id);
else {
printf("Default Boot Loader Entry:\n");
- r = boot_entry_show(config.entries + config.default_entry, /* show_as_default= */ false, /* show_as_selected= */ false);
+ r = boot_entry_show(
+ config.entries + config.default_entry,
+ /* 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 */
else if (r < 0)
log_warning_errno(r, "Failed to determine entries reported by boot loader, ignoring: %m");
else
- (void) boot_entries_augment_from_loader(&config, efi_entries, false);
+ (void) boot_entries_augment_from_loader(&config, efi_entries, /* only_auto= */ false);
if (config.n_entries == 0)
log_info("No boot loader entries found.");
for (size_t n = 0; n < config.n_entries; n++) {
r = boot_entry_show(
config.entries + n,
- n == (size_t) config.default_entry,
- n == (size_t) config.selected_entry);
+ /* show_as_default= */ n == (size_t) config.default_entry,
+ /* show_as_selected= */ n == (size_t) config.selected_entry,
+ /* show_discovered= */ true);
if (r < 0)
return r;
r = manager_read_efi_boot_loader_entries(m);
if (r >= 0)
- (void) boot_entries_augment_from_loader(&config, m->efi_boot_loader_entries, true);
+ (void) boot_entries_augment_from_loader(&config, m->efi_boot_loader_entries, /* auto_only= */ true);
- return boot_config_has_entry(&config, id);
+ return !!boot_config_find_entry(&config, id);
}
static int method_set_reboot_to_boot_loader_entry(
r = manager_read_efi_boot_loader_entries(m);
if (r >= 0)
- (void) boot_entries_augment_from_loader(&config, m->efi_boot_loader_entries, true);
+ (void) boot_entries_augment_from_loader(&config, m->efi_boot_loader_entries, /* auto_only= */ true);
r = sd_bus_message_open_container(reply, 'a', "s");
if (r < 0)
return 0;
}
-static bool find_nonunique(BootEntry *entries, size_t n_entries, bool *arr) {
+static bool find_nonunique(const BootEntry *entries, size_t n_entries, bool arr[]) {
size_t i, j;
bool non_unique = false;
* already included there. */
STRV_FOREACH(i, found_by_loader) {
+ BootEntry *existing;
_cleanup_free_ char *c = NULL, *t = NULL, *p = NULL;
char **a, **b;
- if (boot_config_has_entry(config, *i))
+ existing = boot_config_find_entry(config, *i);
+ if (existing) {
+ existing->reported_by_loader = true;
continue;
+ }
if (only_auto && !startswith(*i, "auto-"))
continue;
return log_oom();
config->entries[config->n_entries++] = (BootEntry) {
- .type = BOOT_ENTRY_LOADER,
+ .type = startswith(*i, "auto-") ? BOOT_ENTRY_LOADER_AUTO : BOOT_ENTRY_LOADER,
.id = TAKE_PTR(c),
.title = TAKE_PTR(t),
.path = TAKE_PTR(p),
+ .reported_by_loader = true,
};
}
#include "string-util.h"
typedef enum BootEntryType {
- BOOT_ENTRY_CONF, /* Type #1 entries: *.conf files */
- BOOT_ENTRY_UNIFIED, /* Type #2 entries: *.efi files */
- BOOT_ENTRY_LOADER, /* Additional entries augmented from LoaderEntries EFI var */
- _BOOT_ENTRY_MAX,
- _BOOT_ENTRY_INVALID = -EINVAL,
+ BOOT_ENTRY_CONF, /* Boot Loader Specification Type #1 entries: *.conf files */
+ BOOT_ENTRY_UNIFIED, /* Boot Loader Specification Type #2 entries: *.efi files */
+ BOOT_ENTRY_LOADER, /* Additional entries augmented from LoaderEntries EFI variable (regular entries) */
+ BOOT_ENTRY_LOADER_AUTO, /* Additional entries augmented from LoaderEntries EFI variable (special "automatic" entries) */
+ _BOOT_ENTRY_TYPE_MAX,
+ _BOOT_ENTRY_TYPE_INVALID = -EINVAL,
} BootEntryType;
typedef struct BootEntry {
BootEntryType type;
+ bool reported_by_loader;
char *id; /* This is the file basename (including extension!) */
char *id_old; /* Old-style ID, for deduplication purposes. */
char *path; /* This is the full path to the drop-in file */
ssize_t selected_entry;
} BootConfig;
-static inline bool boot_config_has_entry(BootConfig *config, const char *id) {
- size_t j;
+static inline BootEntry* boot_config_find_entry(BootConfig *config, const char *id) {
+ assert(config);
+ assert(id);
- for (j = 0; j < config->n_entries; j++) {
- const char* entry_id_old = config->entries[j].id_old;
- if (streq(config->entries[j].id, id) ||
- (entry_id_old && streq(entry_id_old, id)))
- return true;
- }
+ for (size_t j = 0; j < config->n_entries; j++)
+ if (streq_ptr(config->entries[j].id, id) ||
+ streq_ptr(config->entries[j].id_old, id))
+ return config->entries + j;
- return false;
+ return NULL;
}
static inline BootEntry* boot_config_default_entry(BootConfig *config) {
+ assert(config);
+
if (config->default_entry < 0)
return NULL;
int boot_entries_augment_from_loader(BootConfig *config, char **list, bool only_auto);
static inline const char* boot_entry_title(const BootEntry *entry) {
+ assert(entry);
+
return entry->show_title ?: entry->title ?: entry->id;
}