summaryrefslogtreecommitdiffstats
path: root/src/shared/bootspec.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared/bootspec.c')
-rw-r--r--src/shared/bootspec.c105
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) {