Add --efi-boot-option-description argument to bootctl to control the name of the boot

entry.

By default an entry named "Linux Boot Manager" is created (which is the
previous behavior). With the flag the name of the entry can be
controlled, which is useful when installing systemd-boot to multiple ESP
partitions and having uniquely named entries.

Fixes #17044.
This commit is contained in:
Rene Hollander 2022-08-13 21:38:02 +02:00 committed by Lennart Poettering
parent be06a84c8d
commit d9bdb29bf5
2 changed files with 68 additions and 23 deletions

View file

@ -377,6 +377,19 @@
<listitem><para>Install binaries for all supported EFI architectures (this implies <option>--no-variables</option>).</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--efi-boot-option-description=</option></term>
<listitem><para>Description of the entry added to the firmware's boot option list. Defaults to <literal>Linux
Boot Manager</literal>.</para>
<para>Using the default entry name <literal>Linux Boot Manager</literal> 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.</para></listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="no-pager"/>
<xi:include href="standard-options.xml" xpointer="json" />
<xi:include href="standard-options.xml" xpointer="help"/>

View file

@ -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;