diff options
author | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2022-03-18 19:04:48 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-18 19:04:48 +0100 |
commit | 5f1077af1eda0bfee7a7ec68b4912ed8e2d86484 (patch) | |
tree | 0e5dd045faa9632a013316e16040ec5b93e479a9 /src/shared/bootspec.c | |
parent | strv: use STRV_FOREACH() at two more places (diff) | |
parent | update TODO (diff) | |
download | systemd-5f1077af1eda0bfee7a7ec68b4912ed8e2d86484.tar.xz systemd-5f1077af1eda0bfee7a7ec68b4912ed8e2d86484.zip |
Merge pull request #22519 from poettering/boot-order-title-revert
sd-boot: rework boot entry sorting
Diffstat (limited to 'src/shared/bootspec.c')
-rw-r--r-- | src/shared/bootspec.c | 105 |
1 files changed, 73 insertions, 32 deletions
diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c index e34ac539c0..8147204116 100644 --- a/src/shared/bootspec.c +++ b/src/shared/bootspec.c @@ -27,6 +27,7 @@ static void boot_entry_free(BootEntry *entry) { free(entry->root); free(entry->title); free(entry->show_title); + free(entry->sort_key); free(entry->version); free(entry->machine_id); free(entry->architecture); @@ -113,6 +114,8 @@ static int boot_entry_load( if (streq(field, "title")) r = free_and_strdup(&tmp.title, p); + else if (streq(field, "sort-key")) + r = free_and_strdup(&tmp.sort_key, p); else if (streq(field, "version")) r = free_and_strdup(&tmp.version, p); else if (streq(field, "machine-id")) @@ -245,6 +248,28 @@ static int boot_loader_read_conf(const char *path, BootConfig *config) { } static int boot_entry_compare(const BootEntry *a, const BootEntry *b) { + int r; + + assert(a); + assert(b); + + r = CMP(!a->sort_key, !b->sort_key); + if (r != 0) + return r; + if (a->sort_key && b->sort_key) { + r = strcmp(a->sort_key, b->sort_key); + if (r != 0) + return r; + + r = strcmp_ptr(a->machine_id, b->machine_id); + if (r != 0) + return r; + + r = -strverscmp_improved(a->version, b->version); + if (r != 0) + return r; + } + return strverscmp_improved(a->id, b->id); } @@ -293,7 +318,7 @@ static int boot_entry_load_unified( _cleanup_(boot_entry_free) BootEntry tmp = { .type = BOOT_ENTRY_UNIFIED, }; - const char *k, *good_name, *good_version; + const char *k, *good_name, *good_version, *good_sort_key; _cleanup_fclose_ FILE *f = NULL; int r; @@ -321,7 +346,7 @@ static int boot_entry_load_unified( if (r < 0) return log_error_errno(r, "Failed to parse os-release data from unified kernel image %s: %m", path); - if (!bootspec_pick_name_version( + if (!bootspec_pick_name_version_sort_key( os_pretty_name, os_image_id, os_name, @@ -331,7 +356,8 @@ static int boot_entry_load_unified( os_version_id, os_build_id, &good_name, - &good_version)) + &good_version, + &good_sort_key)) return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Missing fields in os-release data from unified kernel image %s, refusing.", path); r = path_extract_filename(path, &tmp.id); @@ -369,6 +395,10 @@ static int boot_entry_load_unified( if (!tmp.title) return log_oom(); + tmp.sort_key = strdup(good_sort_key); + if (!tmp.sort_key) + return log_oom(); + tmp.version = strdup(good_version); if (!tmp.version) return log_oom(); @@ -616,6 +646,19 @@ static int boot_entries_uniquify(BootEntry *entries, size_t n_entries) { return 0; } +static int boot_config_find(const BootConfig *config, const char *id) { + assert(config); + + if (!id) + return -1; + + for (size_t i = 0; i < config->n_entries; i++) + if (fnmatch(id, config->entries[i].id, FNM_CASEFOLD) == 0) + return i; + + return -1; +} + static int boot_entries_select_default(const BootConfig *config) { int i; @@ -627,47 +670,45 @@ static int boot_entries_select_default(const BootConfig *config) { return -1; /* -1 means "no default" */ } - if (config->entry_oneshot) - for (i = config->n_entries - 1; i >= 0; i--) - if (streq(config->entry_oneshot, config->entries[i].id)) { - log_debug("Found default: id \"%s\" is matched by LoaderEntryOneShot", - config->entries[i].id); - return i; - } + if (config->entry_oneshot) { + i = boot_config_find(config, config->entry_oneshot); + if (i >= 0) { + log_debug("Found default: id \"%s\" is matched by LoaderEntryOneShot", + config->entries[i].id); + return i; + } + } - if (config->entry_default) - for (i = config->n_entries - 1; i >= 0; i--) - if (streq(config->entry_default, config->entries[i].id)) { - log_debug("Found default: id \"%s\" is matched by LoaderEntryDefault", - config->entries[i].id); - return i; - } + if (config->entry_default) { + i = boot_config_find(config, config->entry_default); + if (i >= 0) { + log_debug("Found default: id \"%s\" is matched by LoaderEntryDefault", + config->entries[i].id); + return i; + } + } - if (config->default_pattern) - for (i = config->n_entries - 1; i >= 0; i--) - if (fnmatch(config->default_pattern, config->entries[i].id, FNM_CASEFOLD) == 0) { - log_debug("Found default: id \"%s\" is matched by pattern \"%s\"", - config->entries[i].id, config->default_pattern); - return i; - } + if (config->default_pattern) { + i = boot_config_find(config, config->default_pattern); + if (i >= 0) { + log_debug("Found default: id \"%s\" is matched by pattern \"%s\"", + config->entries[i].id, config->default_pattern); + return i; + } + } - log_debug("Found default: last entry \"%s\"", config->entries[config->n_entries - 1].id); - return config->n_entries - 1; + log_debug("Found default: first entry \"%s\"", config->entries[0].id); + return 0; } static int boot_entries_select_selected(const BootConfig *config) { - assert(config); assert(config->entries || config->n_entries == 0); if (!config->entry_selected || config->n_entries == 0) return -1; - for (int i = config->n_entries - 1; i >= 0; i--) - if (streq(config->entry_selected, config->entries[i].id)) - return i; - - return -1; + return boot_config_find(config, config->entry_selected); } static int boot_load_efi_entry_pointers(BootConfig *config) { |