From 6e2a452118cf2cb0071490c8daa6829db45356e7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 25 Mar 2026 18:08:16 +0100 Subject: [PATCH 1/4] fundamental: move strv_isempty() into src/fundamental/ --- src/basic/strv.h | 4 ---- src/boot/boot.c | 2 +- src/fundamental/strv-fundamental.h | 5 +++++ 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/basic/strv.h b/src/basic/strv.h index 7249d8a311..d7c4b2bcf0 100644 --- a/src/basic/strv.h +++ b/src/basic/strv.h @@ -104,10 +104,6 @@ static inline const char* STRV_IFNOTNULL(const char *x) { return x ?: STRV_IGNORE; } -static inline bool strv_isempty(char * const *l) { - return !l || !*l; -} - int strv_split_full(char ***t, const char *s, const char *separators, ExtractFlags flags); char** strv_split(const char *s, const char *separators); diff --git a/src/boot/boot.c b/src/boot/boot.c index bffedf78e2..237e78c5a9 100644 --- a/src/boot/boot.c +++ b/src/boot/boot.c @@ -2547,7 +2547,7 @@ static EFI_STATUS initrd_prepare( assert(ret_initrd_pages); assert(ret_initrd_size); - if (entry->type != LOADER_LINUX || !entry->initrd) { + if (entry->type != LOADER_LINUX || strv_isempty(entry->initrd)) { *ret_options = NULL; *ret_initrd_pages = (Pages) {}; *ret_initrd_size = 0; diff --git a/src/fundamental/strv-fundamental.h b/src/fundamental/strv-fundamental.h index 3abcdc4b02..7e7e34822f 100644 --- a/src/fundamental/strv-fundamental.h +++ b/src/fundamental/strv-fundamental.h @@ -2,9 +2,14 @@ #pragma once #include "macro-fundamental.h" +#include "string-util-fundamental.h" #define _STRV_FOREACH(s, l, i) \ for (typeof(*(l)) *s, *i = (l); (s = i) && *i; i++) #define STRV_FOREACH(s, l) \ _STRV_FOREACH(s, l, UNIQ_T(i, UNIQ)) + +static inline bool strv_isempty(sd_char * const *l) { + return !l || !*l; +} From 3d4e3c1a5e3a4a8c0fa531d205763de58e31bcab Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 26 Mar 2026 23:43:12 +0100 Subject: [PATCH 2/4] boot: properly track internal menu entries When showing the list of menu entries via "p", the "internal call:" field was showing nonsense, since fb6cf4bbb75baee8a6988d899de2c6b3e3805e31. Fix that by adding a proper entry type for "internal" menu items such as reboot/firmware/poweroff, and then check for that. With this in place all entries now have a loader type that makes sense and describes precisely what an entry is about. --- src/boot/boot.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/boot/boot.c b/src/boot/boot.c index 237e78c5a9..1be098c287 100644 --- a/src/boot/boot.c +++ b/src/boot/boot.c @@ -61,6 +61,9 @@ typedef enum LoaderType { LOADER_SECURE_BOOT_KEYS, LOADER_BAD, /* Marker: this boot loader spec type #1 entry is invalid */ LOADER_IGNORE, /* Marker: this boot loader spec type #1 entry does not match local host */ + LOADER_REBOOT, + LOADER_POWEROFF, + LOADER_FWSETUP, _LOADER_TYPE_MAX, } LoaderType; @@ -82,6 +85,9 @@ typedef enum LoaderType { /* Whether to persistently save the selected entry in an EFI variable, if that's requested. */ #define LOADER_TYPE_SAVE_ENTRY(t) IN_SET(t, LOADER_AUTO, LOADER_EFI, LOADER_LINUX, LOADER_UKI, LOADER_UKI_URL, LOADER_TYPE2_UKI) +/* Whether this item is implemented fully inside of systemd-boot */ +#define LOADER_TYPE_IS_INTERNAL(t) IN_SET(t, LOADER_SECURE_BOOT_KEYS, LOADER_REBOOT, LOADER_POWEROFF, LOADER_FWSETUP) + typedef enum { REBOOT_NO, REBOOT_YES, @@ -419,7 +425,7 @@ static void print_status(Config *config, char16_t *loaded_image_path) { printf(" options: %ls\n", entry->options); if (entry->profile > 0) printf(" profile: %u\n", entry->profile); - printf(" internal call: %ls\n", yes_no(!!entry->call)); + printf(" internal call: %ls\n", yes_no(LOADER_TYPE_IS_INTERNAL(entry->type))); printf("counting boots: %ls\n", yes_no(entry->tries_left >= 0)); if (entry->tries_left >= 0) { @@ -3047,6 +3053,7 @@ static void config_add_system_entries(Config *config) { if (config->auto_firmware && FLAGS_SET(get_os_indications_supported(), EFI_OS_INDICATIONS_BOOT_TO_FW_UI)) { BootEntry *entry = xnew(BootEntry, 1); *entry = (BootEntry) { + .type = LOADER_FWSETUP, .id = xstrdup16(u"auto-reboot-to-firmware-setup"), .title = xstrdup16(u"Reboot Into Firmware Interface"), .call = call_reboot_into_firmware, @@ -3059,6 +3066,7 @@ static void config_add_system_entries(Config *config) { if (config->auto_poweroff) { BootEntry *entry = xnew(BootEntry, 1); *entry = (BootEntry) { + .type = LOADER_POWEROFF, .id = xstrdup16(u"auto-poweroff"), .title = xstrdup16(u"Power Off The System"), .call = call_poweroff_system, @@ -3071,6 +3079,7 @@ static void config_add_system_entries(Config *config) { if (config->auto_reboot) { BootEntry *entry = xnew(BootEntry, 1); *entry = (BootEntry) { + .type = LOADER_REBOOT, .id = xstrdup16(u"auto-reboot"), .title = xstrdup16(u"Reboot The System"), .call = call_reboot_system, From 208cc69c5005a7c9edec96ca5109c226126106a6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 26 Mar 2026 23:43:32 +0100 Subject: [PATCH 3/4] boot: do no show pixel width/height in text mode When running in pure text mode (i.e. serial terminal) the pixel width/height is zero and makes no sense to report. Suppress it. --- src/boot/boot.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/boot/boot.c b/src/boot/boot.c index 1be098c287..4a5102f45c 100644 --- a/src/boot/boot.c +++ b/src/boot/boot.c @@ -325,9 +325,13 @@ static void print_status(Config *config, char16_t *loaded_image_path) { secure_boot_mode_to_string(secure)); printf(" shim: %ls\n", yes_no(shim_loaded())); printf(" TPM: %ls\n", yes_no(tpm_present())); - printf(" console mode: %i/%" PRIi64 " (%zux%zu @%ux%u)\n", - ST->ConOut->Mode->Mode, ST->ConOut->Mode->MaxMode - INT64_C(1), - x_max, y_max, screen_width, screen_height); + printf(" console mode: %i/%" PRIi64 " (%zux%zu", + ST->ConOut->Mode->Mode, ST->ConOut->Mode->MaxMode - INT64_C(1), + x_max, y_max); + if (screen_width > 0 && screen_height > 0) + printf(" @ %ux%u", + screen_width, screen_height); + printf(")\n"); if (!ps_continue()) return; From 6a4a4f0302e78fda9ff2cfb7ac6a5644aabc4fc2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 26 Mar 2026 23:44:59 +0100 Subject: [PATCH 4/4] bootspec: honour profile number when sorting properly This corrects sorting of menu entries regarding profile numbers: 1. If the profile number is unset, let's treat this identical to profile 0, when ordering stuff, because an item with no profile is conceptually the same as an item with only a profile 0. 2. Let's take the profile number into account also if sort keys are used. This was makes profiles work sensibly in type 1 entries, via the recently added "profile" stanza. Follow-up for: 5fb90fa3194d998a971b21e4a643670ae5903f85 --- src/boot/boot.c | 12 +++++++++++- src/shared/bootspec.c | 12 +++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/boot/boot.c b/src/boot/boot.c index 4a5102f45c..904f9bf589 100644 --- a/src/boot/boot.c +++ b/src/boot/boot.c @@ -1745,6 +1745,12 @@ static void config_load_smbios_entries( } } +static unsigned boot_entry_profile(const BootEntry *a) { + assert(a); + + return a->profile == UINT_MAX ? 0 : a->profile; +} + static int boot_entry_compare(const BootEntry *a, const BootEntry *b) { int r; @@ -1778,6 +1784,10 @@ static int boot_entry_compare(const BootEntry *a, const BootEntry *b) { r = -strverscmp_improved(a->version, b->version); if (r != 0) return r; + + r = CMP(boot_entry_profile(a), boot_entry_profile(b)); + if (r != 0) + return r; } /* Now order by ID. The version is likely part of the ID, thus note that this will generatelly put @@ -1792,7 +1802,7 @@ static int boot_entry_compare(const BootEntry *a, const BootEntry *b) { /* Note: the strverscmp_improved() call above checked for us that we are looking at the very * same id, hence at this point we only need to compare profile numbers, since we know they * belong to the same UKI. */ - r = CMP(a->profile, b->profile); + r = CMP(boot_entry_profile(a), boot_entry_profile(b)); if (r != 0) return r; } diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c index 2a898067f8..36eb2e7086 100644 --- a/src/shared/bootspec.c +++ b/src/shared/bootspec.c @@ -555,6 +555,12 @@ static int boot_loader_read_conf_path(BootConfig *config, const char *root, cons return boot_loader_read_conf(config, f, full); } +static unsigned boot_entry_profile(const BootEntry *a) { + assert(a); + + return a->profile == UINT_MAX ? 0 : a->profile; +} + static int boot_entry_compare(const BootEntry *a, const BootEntry *b) { int r; @@ -583,6 +589,10 @@ static int boot_entry_compare(const BootEntry *a, const BootEntry *b) { r = -strverscmp_improved(a->version, b->version); if (r != 0) return r; + + r = CMP(boot_entry_profile(a), boot_entry_profile(b)); + if (r != 0) + return r; } r = -strverscmp_improved(a->id_without_profile ?: a->id, b->id_without_profile ?: b->id); @@ -592,7 +602,7 @@ static int boot_entry_compare(const BootEntry *a, const BootEntry *b) { if (a->id_without_profile && b->id_without_profile) { /* The strverscmp_improved() call above already established that we are talking about the * same image here, hence order by profile, if there is one */ - r = CMP(a->profile, b->profile); + r = CMP(boot_entry_profile(a), boot_entry_profile(b)); if (r != 0) return r; }