From 87b4a9eeba1e62fb9bc669488007425a2a591b48 Mon Sep 17 00:00:00 2001 From: Simon de Vlieger Date: Mon, 3 Aug 2026 18:46:09 +0200 Subject: [PATCH] kernel-install: entry_name_format= support Read entry_name_format= from install.conf (or KERNEL_INSTALL_ENTRY_NAME_FORMAT env var) and resolve it using specifier_printf() to produce a configurable entry name. The resolved name is exported as KERNEL_INSTALL_ENTRY_NAME for plugins. Override specifiers: %e - entry token %m - machine ID (kernel-install's resolved machine ID) %v - kernel version being installed (overrides standard %v) All COMMON_SYSTEM_SPECIFIERS are also available (%a for architecture, %A for IMAGE_VERSION, %M for IMAGE_ID, etc.). Default format is "%e-%v", preserving the existing $ENTRY_TOKEN-$KERNEL_VERSION behavior. --- src/kernel-install/kernel-install.c | 88 ++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 3 deletions(-) diff --git a/src/kernel-install/kernel-install.c b/src/kernel-install/kernel-install.c index 8f5be2b42b4..be097cd5cd5 100644 --- a/src/kernel-install/kernel-install.c +++ b/src/kernel-install/kernel-install.c @@ -35,6 +35,7 @@ #include "path-util.h" #include "recurse-dir.h" #include "rm-rf.h" +#include "specifier.h" #include "stat-util.h" #include "string-table.h" #include "string-util.h" @@ -108,12 +109,19 @@ typedef struct Context { char **initrds; char *initrd_generator; char *uki_generator; + char *entry_name_format; + char *entry_name; char *staging_area; char **plugins; char **argv; char **envp; } Context; +/* Longest filename suffix plugins append to the entry name (from 90-uki-copy.install) */ +#define ENTRY_NAME_SUFFIX_MAX STRLEN(".efi.extra.d") + +#define DEFAULT_ENTRY_NAME_FORMAT "%e-%v" + #define CONTEXT_NULL \ (Context) { \ .rfd = XAT_FDROOT, \ @@ -137,6 +145,8 @@ static void context_done(Context *c) { strv_free(c->initrds); free(c->initrd_generator); free(c->uki_generator); + free(c->entry_name_format); + free(c->entry_name); if (c->action == ACTION_INSPECT) free(c->staging_area); else @@ -199,6 +209,9 @@ static int context_copy(const Context *source, Context *ret) { if (r < 0) return r; r = strdup_to(©.uki_generator, source->uki_generator); + if (r < 0) + return r; + r = strdup_to(©.entry_name_format, source->entry_name_format); if (r < 0) return r; r = strdup_to(©.staging_area, source->staging_area); @@ -327,6 +340,63 @@ static int context_set_uki_generator(Context *c, const char *s, const char *sour return context_set_string(s, source, "UKI_GENERATOR", &c->uki_generator); } +static int context_set_entry_name_format(Context *c, const char *s, const char *source) { + assert(c); + return context_set_string(s, source, "ENTRY_NAME_FORMAT", &c->entry_name_format); +} + +static int context_resolve_entry_name(Context *c) { + assert(c); + + if (c->entry_name) + return 0; + + const Specifier table[] = { + { 'e', specifier_string, c->entry_token }, + { 'm', specifier_id128, &c->machine_id }, + { 'v', specifier_string, c->version ?: "KERNEL_VERSION" }, + { 'a', specifier_architecture, NULL }, + { 'A', specifier_os_image_version, NULL }, + { 'B', specifier_os_build_id, NULL }, + { 'H', specifier_hostname, NULL }, + { 'l', specifier_short_hostname, NULL }, + { 'q', specifier_pretty_hostname, NULL }, + { 'M', specifier_os_image_id, NULL }, + { 'o', specifier_os_id, NULL }, + { 'w', specifier_os_version_id, NULL }, + { 'W', specifier_os_variant_id, NULL }, + {} + }; + + _cleanup_free_ char *resolved = NULL; + int r; + + r = specifier_printf( + c->entry_name_format ?: DEFAULT_ENTRY_NAME_FORMAT, + NAME_MAX - ENTRY_NAME_SUFFIX_MAX, + table, + arg_root, + /* userdata= */ c, + &resolved); + if (r < 0) + return log_error_errno(r, "Failed to expand entry name format '%s': %m", + c->entry_name_format ?: DEFAULT_ENTRY_NAME_FORMAT); + + if (isempty(resolved)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Entry name format '%s' resolved to empty string.", + c->entry_name_format ?: DEFAULT_ENTRY_NAME_FORMAT); + + if (!filename_is_valid(resolved)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Entry name format '%s' resolved to invalid filename: %s", + c->entry_name_format ?: DEFAULT_ENTRY_NAME_FORMAT, resolved); + + c->entry_name = TAKE_PTR(resolved); + log_debug("Using entry name: %s", c->entry_name); + return 0; +} + static int context_set_version(Context *c, const char *s) { assert(c); @@ -449,12 +519,14 @@ static int context_load_environment(Context *c) { (void) context_set_boot_root(c, getenv("BOOT_ROOT"), "environment"); (void) context_set_conf_root(c, getenv("KERNEL_INSTALL_CONF_ROOT"), "environment"); (void) context_set_plugins(c, getenv("KERNEL_INSTALL_PLUGINS"), "environment"); + (void) context_set_entry_name_format(c, getenv("KERNEL_INSTALL_ENTRY_NAME_FORMAT"), "environment"); return 0; } static int context_load_install_conf(Context *c) { _cleanup_free_ char *machine_id = NULL, *boot_root = NULL, *layout = NULL, - *initrd_generator = NULL, *uki_generator = NULL; + *initrd_generator = NULL, *uki_generator = NULL, + *entry_name_format = NULL; int r; assert(c); @@ -468,7 +540,7 @@ static int context_load_install_conf(Context *c) { &layout, &initrd_generator, &uki_generator, - /* ret_entry_name_format= */ NULL); + &entry_name_format); if (r <= 0) return r; @@ -477,6 +549,7 @@ static int context_load_install_conf(Context *c) { (void) context_set_layout(c, layout, "config"); (void) context_set_initrd_generator(c, initrd_generator, "config"); (void) context_set_uki_generator(c, uki_generator, "config"); + (void) context_set_entry_name_format(c, entry_name_format, "config"); log_debug("Loaded config."); return 0; @@ -1033,6 +1106,10 @@ static int context_build_environment(Context *c) { if (c->envp) return 0; + r = context_resolve_entry_name(c); + if (r < 0) + return r; + r = strv_env_assign_many(&e, "LC_COLLATE", SYSTEMD_DEFAULT_LOCALE, "KERNEL_INSTALL_VERBOSE", one_zero(arg_verbose), @@ -1044,7 +1121,8 @@ static int context_build_environment(Context *c) { "KERNEL_INSTALL_INITRD_GENERATOR", strempty(c->initrd_generator), "KERNEL_INSTALL_UKI_GENERATOR", strempty(c->uki_generator), "KERNEL_INSTALL_BOOT_ENTRY_TYPE", boot_entry_type_to_string(c->entry_type), - "KERNEL_INSTALL_STAGING_AREA", c->staging_area); + "KERNEL_INSTALL_STAGING_AREA", c->staging_area, + "KERNEL_INSTALL_ENTRY_NAME", c->entry_name); if (r < 0) return log_error_errno(r, "Failed to build environment variables for plugins: %m"); @@ -1414,6 +1492,10 @@ static int verb_inspect(int argc, char *argv[], uintptr_t _data, void *userdata) TABLE_STRING, boot_entry_token_type_to_string(c.entry_token_type), TABLE_FIELD, "Entry Token", TABLE_STRING, c.entry_token, + TABLE_FIELD, "Entry Name Format", + TABLE_STRING, c.entry_name_format ?: DEFAULT_ENTRY_NAME_FORMAT, + TABLE_FIELD, "Entry Name", + TABLE_STRING, c.entry_name, TABLE_FIELD, "Entry Directory", TABLE_STRING, c.entry_dir, TABLE_FIELD, "Kernel Version",