diff --git a/man/bootctl.xml b/man/bootctl.xml
index 1664f68157a..85820ff6068 100644
--- a/man/bootctl.xml
+++ b/man/bootctl.xml
@@ -377,6 +377,19 @@
Install binaries for all supported EFI architectures (this implies ).
+
+
+ Description of the entry added to the firmware's boot option list. Defaults to Linux
+ Boot Manager.
+
+ Using the default entry name Linux Boot Manager is generally preferable as only
+ one bootloader installed to a single ESP partition should be used to boot any number of OS installations
+ found on the various disks installed in the system. Specifically distributions should not use this flag
+ to install a branded entry in the boot option list. However in situations with multiple disks, each with
+ their own ESP partition, it can be beneficial to make it easier to identify the bootloader being used in
+ the firmware's boot option menu.
+
+
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index 10da1c8d7f2..ddeeed0c3d0 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -57,6 +57,12 @@
#include "verbs.h"
#include "virt.h"
+/* EFI_BOOT_OPTION_DESCRIPTION_MAX sets the maximum length for the boot option description
+ * stored in NVRAM. The UEFI spec does not specify a minimum or maximum length for this
+ * string, but we limit the length to something reasonable to prevent from the firmware
+ * having to deal with a potentially too long string. */
+#define EFI_BOOT_OPTION_DESCRIPTION_MAX ((size_t) 255)
+
static char *arg_esp_path = NULL;
static char *arg_xbootldr_path = NULL;
static bool arg_print_esp_path = false;
@@ -85,6 +91,7 @@ static enum {
ARG_INSTALL_SOURCE_HOST,
ARG_INSTALL_SOURCE_AUTO,
} arg_install_source = ARG_INSTALL_SOURCE_AUTO;
+static char *arg_efi_boot_option_description = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_esp_path, freep);
STATIC_DESTRUCTOR_REGISTER(arg_xbootldr_path, freep);
@@ -92,12 +99,17 @@ STATIC_DESTRUCTOR_REGISTER(arg_install_layout, freep);
STATIC_DESTRUCTOR_REGISTER(arg_entry_token, freep);
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_efi_boot_option_description, freep);
static const char *arg_dollar_boot_path(void) {
/* $BOOT shall be the XBOOTLDR partition if it exists, and otherwise the ESP */
return arg_xbootldr_path ?: arg_esp_path;
}
+static const char *pick_efi_boot_option_description(void) {
+ return arg_efi_boot_option_description ?: "Linux Boot Manager";
+}
+
static int acquire_esp(
bool unprivileged_mode,
bool graceful,
@@ -321,7 +333,7 @@ static int settle_entry_token(void) {
break;
}
- if (isempty(arg_entry_token) || !string_is_safe(arg_entry_token))
+ if (isempty(arg_entry_token) || !(utf8_is_valid(arg_entry_token) && string_is_safe(arg_entry_token)))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Selected entry token not valid: %s", arg_entry_token);
log_debug("Using entry token: %s", arg_entry_token);
@@ -1139,13 +1151,13 @@ static int install_variables(const char *esp_path,
"Failed to determine current boot order: %m");
if (first || r == 0) {
- r = efi_add_boot_option(slot, "Linux Boot Manager",
+ r = efi_add_boot_option(slot, pick_efi_boot_option_description(),
part, pstart, psize,
uuid, path);
if (r < 0)
return log_error_errno(r, "Failed to create EFI Boot variable entry: %m");
- log_info("Created EFI boot entry \"Linux Boot Manager\".");
+ log_info("Created EFI boot entry \"%s\".", pick_efi_boot_option_description());
}
return insert_into_order(slot, first);
@@ -1465,6 +1477,8 @@ static int help(int argc, char *argv[], void *userdata) {
" Generate JSON output\n"
" --all-architectures\n"
" Install all supported EFI architectures\n"
+ " --efi-boot-option-description=DESCRIPTION\n"
+ " Description of the entry in the boot option list\n"
"\nSee the %2$s for details.\n",
program_invocation_short_name,
link,
@@ -1491,29 +1505,31 @@ static int parse_argv(int argc, char *argv[]) {
ARG_ENTRY_TOKEN,
ARG_JSON,
ARG_ARCH_ALL,
+ ARG_EFI_BOOT_OPTION_DESCRIPTION,
};
static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, ARG_VERSION },
- { "esp-path", required_argument, NULL, ARG_ESP_PATH },
- { "path", required_argument, NULL, ARG_ESP_PATH }, /* Compatibility alias */
- { "boot-path", required_argument, NULL, ARG_BOOT_PATH },
- { "root", required_argument, NULL, ARG_ROOT },
- { "image", required_argument, NULL, ARG_IMAGE },
- { "install-source", required_argument, NULL, ARG_INSTALL_SOURCE },
- { "print-esp-path", no_argument, NULL, 'p' },
- { "print-path", no_argument, NULL, 'p' }, /* Compatibility alias */
- { "print-boot-path", no_argument, NULL, 'x' },
- { "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
- { "no-pager", no_argument, NULL, ARG_NO_PAGER },
- { "graceful", no_argument, NULL, ARG_GRACEFUL },
- { "quiet", no_argument, NULL, 'q' },
- { "make-entry-directory", required_argument, NULL, ARG_MAKE_ENTRY_DIRECTORY },
- { "make-machine-id-directory", required_argument, NULL, ARG_MAKE_ENTRY_DIRECTORY }, /* Compatibility alias */
- { "entry-token", required_argument, NULL, ARG_ENTRY_TOKEN },
- { "json", required_argument, NULL, ARG_JSON },
- { "all-architectures", no_argument, NULL, ARG_ARCH_ALL },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, ARG_VERSION },
+ { "esp-path", required_argument, NULL, ARG_ESP_PATH },
+ { "path", required_argument, NULL, ARG_ESP_PATH }, /* Compatibility alias */
+ { "boot-path", required_argument, NULL, ARG_BOOT_PATH },
+ { "root", required_argument, NULL, ARG_ROOT },
+ { "image", required_argument, NULL, ARG_IMAGE },
+ { "install-source", required_argument, NULL, ARG_INSTALL_SOURCE },
+ { "print-esp-path", no_argument, NULL, 'p' },
+ { "print-path", no_argument, NULL, 'p' }, /* Compatibility alias */
+ { "print-boot-path", no_argument, NULL, 'x' },
+ { "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
+ { "no-pager", no_argument, NULL, ARG_NO_PAGER },
+ { "graceful", no_argument, NULL, ARG_GRACEFUL },
+ { "quiet", no_argument, NULL, 'q' },
+ { "make-entry-directory", required_argument, NULL, ARG_MAKE_ENTRY_DIRECTORY },
+ { "make-machine-id-directory", required_argument, NULL, ARG_MAKE_ENTRY_DIRECTORY }, /* Compatibility alias */
+ { "entry-token", required_argument, NULL, ARG_ENTRY_TOKEN },
+ { "json", required_argument, NULL, ARG_JSON },
+ { "all-architectures", no_argument, NULL, ARG_ARCH_ALL },
+ { "efi-boot-option-description", required_argument, NULL, ARG_EFI_BOOT_OPTION_DESCRIPTION },
{}
};
@@ -1647,6 +1663,22 @@ static int parse_argv(int argc, char *argv[]) {
arg_arch_all = true;
break;
+ case ARG_EFI_BOOT_OPTION_DESCRIPTION:
+ if (isempty(optarg) || !(string_is_safe(optarg) && utf8_is_valid(optarg))) {
+ _cleanup_free_ char *escaped = NULL;
+
+ escaped = cescape(optarg);
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Invalid --efi-boot-option-description=: %s", strna(escaped));
+ }
+ if (strlen(optarg) > EFI_BOOT_OPTION_DESCRIPTION_MAX)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "--efi-boot-option-description= too long: %zu > %zu", strlen(optarg), EFI_BOOT_OPTION_DESCRIPTION_MAX);
+ r = free_and_strdup_warn(&arg_efi_boot_option_description, optarg);
+ if (r < 0)
+ return r;
+ break;
+
case '?':
return -EINVAL;