Compare commits

...

2 Commits

Author SHA1 Message Date
Adrian Vovk 7d7045da7a
Merge be7d9867ed into bbec1c87d3 2024-11-26 21:47:06 +00:00
Adrian Vovk be7d9867ed
bootspec: Look at /loader/addons in XBOOTLDR
The bootspec util-lib's handling of global addons didn't previously
match the behavior of sd-stub, and this commit corrects that.

First, bootspec didn't load global addons from the XBOOTLDR dir, but the
stub does. So, bootspec now enumerates addons in XBOOTLDR, not just ESP

Second, the stub only loads resources (including addons) from the
partition that it was found on. Thus, we must keep track of which
partition the global addons come from, and which partition each boot
entry comes from. In other words: global addons found on the ESP will
NOT apply to UKIs found in XBOOTLDR, and bootspec now reflects that.
2024-11-26 16:46:34 -05:00
4 changed files with 75 additions and 30 deletions

View File

@ -92,7 +92,6 @@ static int status_entries(
r = show_boot_entry( r = show_boot_entry(
boot_config_default_entry(config), boot_config_default_entry(config),
&config->global_addons,
/* show_as_default= */ false, /* show_as_default= */ false,
/* show_as_selected= */ false, /* show_as_selected= */ false,
/* show_discovered= */ false); /* show_discovered= */ false);

View File

@ -55,7 +55,7 @@ static int json_dispatch_entries(const char *name, sd_json_variant *variant, sd_
_cleanup_fclose_ FILE *f = NULL; _cleanup_fclose_ FILE *f = NULL;
assert_se(f = data_to_file((const uint8_t*) data, len)); assert_se(f = data_to_file((const uint8_t*) data, len));
assert_se(boot_config_load_type1(config, f, "/", "/entries", id) != -ENOMEM); assert_se(boot_config_load_type1(config, f, "/", BOOT_ENTRY_ESP, "/entries", id) != -ENOMEM);
} }
} }

View File

@ -44,6 +44,20 @@ static const char* const boot_entry_type_json_table[_BOOT_ENTRY_TYPE_MAX] = {
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(boot_entry_type_json, BootEntryType); DEFINE_STRING_TABLE_LOOKUP_TO_STRING(boot_entry_type_json, BootEntryType);
static const char* const boot_entry_source_table[_BOOT_ENTRY_SOURCE_MAX] = {
[BOOT_ENTRY_ESP] = "EFI System Partition",
[BOOT_ENTRY_XBOOTLDR] = "Extended Boot Loader Partition",
};
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(boot_entry_source, BootEntrySource);
static const char* const boot_entry_source_json_table[_BOOT_ENTRY_SOURCE_MAX] = {
[BOOT_ENTRY_ESP] = "esp",
[BOOT_ENTRY_XBOOTLDR] = "xbootldr",
};
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(boot_entry_source_json, BootEntrySource);
static void boot_entry_addons_done(BootEntryAddons *addons); static void boot_entry_addons_done(BootEntryAddons *addons);
static void boot_entry_free(BootEntry *entry) { static void boot_entry_free(BootEntry *entry) {
@ -285,11 +299,12 @@ nothing:
static int boot_entry_load_type1( static int boot_entry_load_type1(
FILE *f, FILE *f,
const char *root, const char *root,
const BootEntrySource source,
const char *dir, const char *dir,
const char *fname, const char *fname,
BootEntry *entry) { BootEntry *entry) {
_cleanup_(boot_entry_free) BootEntry tmp = BOOT_ENTRY_INIT(BOOT_ENTRY_CONF); _cleanup_(boot_entry_free) BootEntry tmp = BOOT_ENTRY_INIT(BOOT_ENTRY_CONF, source);
char *c; char *c;
int r; int r;
@ -395,6 +410,7 @@ int boot_config_load_type1(
BootConfig *config, BootConfig *config,
FILE *f, FILE *f,
const char *root, const char *root,
const BootEntrySource source,
const char *dir, const char *dir,
const char *fname) { const char *fname) {
int r; int r;
@ -408,10 +424,14 @@ int boot_config_load_type1(
if (!GREEDY_REALLOC0(config->entries, config->n_entries + 1)) if (!GREEDY_REALLOC0(config->entries, config->n_entries + 1))
return log_oom(); return log_oom();
r = boot_entry_load_type1(f, root, dir, fname, config->entries + config->n_entries); BootEntry *entry = config->entries + config->n_entries;
r = boot_entry_load_type1(f, root, source, dir, fname, entry);
if (r < 0) if (r < 0)
return r; return r;
entry->global_addons = &config->global_addons[source];
config->n_entries++; config->n_entries++;
return 0; return 0;
} }
@ -429,7 +449,8 @@ void boot_config_free(BootConfig *config) {
boot_entry_free(i); boot_entry_free(i);
free(config->entries); free(config->entries);
boot_entry_addons_done(&config->global_addons); FOREACH_ARRAY(i, config->global_addons, _BOOT_ENTRY_SOURCE_MAX)
boot_entry_addons_done(i);
set_free(config->inodes_seen); set_free(config->inodes_seen);
} }
@ -595,6 +616,7 @@ static int config_check_inode_relevant_and_unseen(BootConfig *config, int fd, co
static int boot_entries_find_type1( static int boot_entries_find_type1(
BootConfig *config, BootConfig *config,
const char *root, const char *root,
const BootEntrySource source,
const char *dir) { const char *dir) {
_cleanup_free_ DirectoryEntries *dentries = NULL; _cleanup_free_ DirectoryEntries *dentries = NULL;
@ -638,7 +660,7 @@ static int boot_entries_find_type1(
if (r == 0) /* inode already seen or otherwise not relevant */ if (r == 0) /* inode already seen or otherwise not relevant */
continue; continue;
r = boot_config_load_type1(config, f, root, full, de->d_name); r = boot_config_load_type1(config, f, root, source, full, de->d_name);
if (r == -ENOMEM) /* ignore all other errors */ if (r == -ENOMEM) /* ignore all other errors */
return log_oom(); return log_oom();
} }
@ -648,6 +670,7 @@ static int boot_entries_find_type1(
static int boot_entry_load_unified( static int boot_entry_load_unified(
const char *root, const char *root,
const BootEntrySource source,
const char *path, const char *path,
unsigned profile, unsigned profile,
const char *osrelease_text, const char *osrelease_text,
@ -720,7 +743,7 @@ static int boot_entry_load_unified(
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to extract file name from '%s': %m", path); return log_error_errno(r, "Failed to extract file name from '%s': %m", path);
_cleanup_(boot_entry_free) BootEntry tmp = BOOT_ENTRY_INIT(BOOT_ENTRY_UNIFIED); _cleanup_(boot_entry_free) BootEntry tmp = BOOT_ENTRY_INIT(BOOT_ENTRY_UNIFIED, source);
r = boot_filename_extract_tries(fname, &tmp.id, &tmp.tries_left, &tmp.tries_done); r = boot_filename_extract_tries(fname, &tmp.id, &tmp.tries_left, &tmp.tries_done);
if (r < 0) if (r < 0)
@ -1133,18 +1156,21 @@ static int boot_entries_find_unified_addons(
static int boot_entries_find_unified_global_addons( static int boot_entries_find_unified_global_addons(
BootConfig *config, BootConfig *config,
const char *root, const char *root,
const char *d_name) { const char *d_name,
BootEntryAddons *ret_addons) {
int r; int r;
_cleanup_closedir_ DIR *d = NULL; _cleanup_closedir_ DIR *d = NULL;
assert(ret_addons);
r = chase_and_opendir(root, NULL, CHASE_PROHIBIT_SYMLINKS, NULL, &d); r = chase_and_opendir(root, NULL, CHASE_PROHIBIT_SYMLINKS, NULL, &d);
if (r == -ENOENT) if (r == -ENOENT)
return 0; return 0;
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to open '%s/%s': %m", root, d_name); return log_error_errno(r, "Failed to open '%s/%s': %m", root, d_name);
return boot_entries_find_unified_addons(config, dirfd(d), d_name, root, &config->global_addons); return boot_entries_find_unified_addons(config, dirfd(d), d_name, root, ret_addons);
} }
static int boot_entries_find_unified_local_addons( static int boot_entries_find_unified_local_addons(
@ -1168,6 +1194,7 @@ static int boot_entries_find_unified_local_addons(
static int boot_entries_find_unified( static int boot_entries_find_unified(
BootConfig *config, BootConfig *config,
const char *root, const char *root,
BootEntrySource source,
const char *dir) { const char *dir) {
_cleanup_closedir_ DIR *d = NULL; _cleanup_closedir_ DIR *d = NULL;
@ -1220,12 +1247,15 @@ static int boot_entries_find_unified(
BootEntry *entry = config->entries + config->n_entries; BootEntry *entry = config->entries + config->n_entries;
if (boot_entry_load_unified(root, j, p, osrelease, profile, cmdline, entry) < 0) if (boot_entry_load_unified(root, source, j, p, osrelease, profile, cmdline, config->entries + config->n_entries) < 0)
continue; continue;
/* look for .efi.extra.d */ /* look for .efi.extra.d */
(void) boot_entries_find_unified_local_addons(config, dirfd(d), de->d_name, full, entry); (void) boot_entries_find_unified_local_addons(config, dirfd(d), de->d_name, full, entry);
/* Set up the backpointer, so that we can find the global addons */
entry->global_addons = &config->global_addons[source];
config->n_entries++; config->n_entries++;
} }
} }
@ -1443,32 +1473,37 @@ int boot_config_load(
int r; int r;
assert(config); assert(config);
config->global_addons = (BootEntryAddons) {};
if (esp_path) { if (esp_path) {
r = boot_loader_read_conf_path(config, esp_path, "/loader/loader.conf"); r = boot_loader_read_conf_path(config, esp_path, "/loader/loader.conf");
if (r < 0) if (r < 0)
return r; return r;
r = boot_entries_find_type1(config, esp_path, "/loader/entries"); r = boot_entries_find_type1(config, esp_path, BOOT_ENTRY_ESP, "/loader/entries");
if (r < 0) if (r < 0)
return r; return r;
r = boot_entries_find_unified(config, esp_path, "/EFI/Linux/"); r = boot_entries_find_unified(config, esp_path, BOOT_ENTRY_ESP, "/EFI/Linux/");
if (r < 0) if (r < 0)
return r; return r;
r = boot_entries_find_unified_global_addons(config, esp_path, "/loader/addons/"); r = boot_entries_find_unified_global_addons(config, esp_path, "/loader/addons/",
&config->global_addons[BOOT_ENTRY_ESP]);
if (r < 0) if (r < 0)
return r; return r;
} }
if (xbootldr_path) { if (xbootldr_path) {
r = boot_entries_find_type1(config, xbootldr_path, "/loader/entries"); r = boot_entries_find_type1(config, xbootldr_path, BOOT_ENTRY_XBOOTLDR, "/loader/entries");
if (r < 0) if (r < 0)
return r; return r;
r = boot_entries_find_unified(config, xbootldr_path, "/EFI/Linux/"); r = boot_entries_find_unified(config, xbootldr_path, BOOT_ENTRY_XBOOTLDR, "/EFI/Linux/");
if (r < 0)
return r;
r = boot_entries_find_unified_global_addons(config, xbootldr_path, "/loader/addons/",
&config->global_addons[BOOT_ENTRY_XBOOTLDR]);
if (r < 0) if (r < 0)
return r; return r;
} }
@ -1651,9 +1686,7 @@ static int indent_embedded_newlines(char *cmdline, char **ret_cmdline) {
return 0; return 0;
} }
static int print_cmdline( static int print_cmdline(const BootEntry *e) {
const BootEntry *e,
const BootEntryAddons *global_arr) {
_cleanup_free_ char *options = NULL, *combined_cmdline = NULL, *t2 = NULL; _cleanup_free_ char *options = NULL, *combined_cmdline = NULL, *t2 = NULL;
@ -1675,7 +1708,7 @@ static int print_cmdline(
return log_oom(); return log_oom();
} }
FOREACH_ARRAY(addon, global_arr->items, global_arr->n_items) { FOREACH_ARRAY(addon, e->global_addons->items, e->global_addons->n_items) {
print_addon(addon, "global-addon"); print_addon(addon, "global-addon");
if (!strextend(&t2, " ", addon->cmdline)) if (!strextend(&t2, " ", addon->cmdline))
return log_oom(); return log_oom();
@ -1723,7 +1756,6 @@ static int json_addon(
static int json_cmdline( static int json_cmdline(
const BootEntry *e, const BootEntry *e,
const BootEntryAddons *global_arr,
const char *def_cmdline, const char *def_cmdline,
sd_json_variant **v) { sd_json_variant **v) {
@ -1739,7 +1771,7 @@ static int json_cmdline(
return log_oom(); return log_oom();
} }
FOREACH_ARRAY(addon, global_arr->items, global_arr->n_items) { FOREACH_ARRAY(addon, e->global_addons->items, e->global_addons->n_items) {
r = json_addon(addon, "globalAddon", &addons_array); r = json_addon(addon, "globalAddon", &addons_array);
if (r < 0) if (r < 0)
return r; return r;
@ -1766,7 +1798,6 @@ static int json_cmdline(
int show_boot_entry( int show_boot_entry(
const BootEntry *e, const BootEntry *e,
const BootEntryAddons *global_addons,
bool show_as_default, bool show_as_default,
bool show_as_selected, bool show_as_selected,
bool show_reported) { bool show_reported) {
@ -1826,7 +1857,9 @@ int show_boot_entry(
if (e->type == BOOT_ENTRY_CONF) if (e->type == BOOT_ENTRY_CONF)
(void) terminal_urlify_path(e->path, text, &link); (void) terminal_urlify_path(e->path, text, &link);
printf(" source: %s\n", link ?: text ?: e->path); printf(" source: %s (on the %s)\n",
link ?: text ?: e->path,
boot_entry_source_to_string(e->source));
} }
if (e->tries_left != UINT_MAX) { if (e->tries_left != UINT_MAX) {
printf(" tries: %u left", e->tries_left); printf(" tries: %u left", e->tries_left);
@ -1856,7 +1889,7 @@ int show_boot_entry(
*s, *s,
&status); &status);
r = print_cmdline(e, global_addons); r = print_cmdline(e);
if (r < 0) if (r < 0)
return r; return r;
@ -1897,6 +1930,7 @@ int boot_entry_to_json(const BootConfig *c, size_t i, sd_json_variant **ret) {
r = sd_json_variant_merge_objectbo( r = sd_json_variant_merge_objectbo(
&v, &v,
SD_JSON_BUILD_PAIR("type", SD_JSON_BUILD_STRING(boot_entry_type_json_to_string(e->type))), SD_JSON_BUILD_PAIR("type", SD_JSON_BUILD_STRING(boot_entry_type_json_to_string(e->type))),
SD_JSON_BUILD_PAIR("source", SD_JSON_BUILD_STRING(boot_entry_source_json_to_string(e->source))),
SD_JSON_BUILD_PAIR_CONDITION(!!e->id, "id", SD_JSON_BUILD_STRING(e->id)), SD_JSON_BUILD_PAIR_CONDITION(!!e->id, "id", SD_JSON_BUILD_STRING(e->id)),
SD_JSON_BUILD_PAIR_CONDITION(!!e->path, "path", SD_JSON_BUILD_STRING(e->path)), SD_JSON_BUILD_PAIR_CONDITION(!!e->path, "path", SD_JSON_BUILD_STRING(e->path)),
SD_JSON_BUILD_PAIR_CONDITION(!!e->root, "root", SD_JSON_BUILD_STRING(e->root)), SD_JSON_BUILD_PAIR_CONDITION(!!e->root, "root", SD_JSON_BUILD_STRING(e->root)),
@ -1928,7 +1962,7 @@ int boot_entry_to_json(const BootConfig *c, size_t i, sd_json_variant **ret) {
if (r < 0) if (r < 0)
return log_oom(); return log_oom();
r = json_cmdline(e, &c->global_addons, opts, &v); r = json_cmdline(e, opts, &v);
if (r < 0) if (r < 0)
return log_oom(); return log_oom();
@ -1961,7 +1995,6 @@ int show_boot_entries(const BootConfig *config, sd_json_format_flags_t json_form
for (size_t n = 0; n < config->n_entries; n++) { for (size_t n = 0; n < config->n_entries; n++) {
r = show_boot_entry( r = show_boot_entry(
config->entries + n, config->entries + n,
&config->global_addons,
/* show_as_default= */ n == (size_t) config->default_entry, /* show_as_default= */ n == (size_t) config->default_entry,
/* show_as_selected= */ n == (size_t) config->selected_entry, /* show_as_selected= */ n == (size_t) config->selected_entry,
/* show_discovered= */ true); /* show_discovered= */ true);

View File

@ -21,6 +21,13 @@ typedef enum BootEntryType {
_BOOT_ENTRY_TYPE_INVALID = -EINVAL, _BOOT_ENTRY_TYPE_INVALID = -EINVAL,
} BootEntryType; } BootEntryType;
typedef enum BootEntrySource {
BOOT_ENTRY_ESP,
BOOT_ENTRY_XBOOTLDR,
_BOOT_ENTRY_SOURCE_MAX,
_BOOT_ENTRY_SOURCE_INVALID = -EINVAL,
} BootEntrySource;
typedef struct BootEntryAddon { typedef struct BootEntryAddon {
char *location; char *location;
char *cmdline; char *cmdline;
@ -33,6 +40,7 @@ typedef struct BootEntryAddons {
typedef struct BootEntry { typedef struct BootEntry {
BootEntryType type; BootEntryType type;
BootEntrySource source;
bool reported_by_loader; bool reported_by_loader;
char *id; /* This is the file basename (including extension!) */ char *id; /* This is the file basename (including extension!) */
char *id_old; /* Old-style ID, for deduplication purposes. */ char *id_old; /* Old-style ID, for deduplication purposes. */
@ -47,6 +55,7 @@ typedef struct BootEntry {
char *architecture; char *architecture;
char **options; char **options;
BootEntryAddons local_addons; BootEntryAddons local_addons;
const BootEntryAddons *global_addons; /* Backpointer into the BootConfig; we don't own this here */
char *kernel; /* linux is #defined to 1, yikes! */ char *kernel; /* linux is #defined to 1, yikes! */
char *efi; char *efi;
char **initrd; char **initrd;
@ -57,9 +66,10 @@ typedef struct BootEntry {
unsigned profile; unsigned profile;
} BootEntry; } BootEntry;
#define BOOT_ENTRY_INIT(t) \ #define BOOT_ENTRY_INIT(t, s) \
{ \ { \
.type = (t), \ .type = (t), \
.source = (s), \
.tries_left = UINT_MAX, \ .tries_left = UINT_MAX, \
.tries_done = UINT_MAX, \ .tries_done = UINT_MAX, \
} }
@ -74,7 +84,7 @@ typedef struct BootConfig {
BootEntry *entries; BootEntry *entries;
size_t n_entries; size_t n_entries;
BootEntryAddons global_addons; BootEntryAddons global_addons[_BOOT_ENTRY_SOURCE_MAX];
ssize_t default_entry; ssize_t default_entry;
ssize_t selected_entry; ssize_t selected_entry;
@ -91,6 +101,9 @@ typedef struct BootConfig {
const char* boot_entry_type_to_string(BootEntryType); const char* boot_entry_type_to_string(BootEntryType);
const char* boot_entry_type_json_to_string(BootEntryType); const char* boot_entry_type_json_to_string(BootEntryType);
const char* boot_entry_source_to_string(BootEntrySource);
const char* boot_entry_source_json_to_string(BootEntrySource);
BootEntry* boot_config_find_entry(BootConfig *config, const char *id); BootEntry* boot_config_find_entry(BootConfig *config, const char *id);
static inline const BootEntry* boot_config_default_entry(const BootConfig *config) { static inline const BootEntry* boot_config_default_entry(const BootConfig *config) {
@ -111,6 +124,7 @@ int boot_config_load_type1(
BootConfig *config, BootConfig *config,
FILE *f, FILE *f,
const char *root, const char *root,
const BootEntrySource source,
const char *dir, const char *dir,
const char *id); const char *id);
@ -129,7 +143,6 @@ static inline const char* boot_entry_title(const BootEntry *entry) {
int show_boot_entry( int show_boot_entry(
const BootEntry *e, const BootEntry *e,
const BootEntryAddons *global_addons,
bool show_as_default, bool show_as_default,
bool show_as_selected, bool show_as_selected,
bool show_reported); bool show_reported);