Skip to content

Commit

Permalink
Add --efi-label argument to bootctl to control the name of the boot
Browse files Browse the repository at this point in the history
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 systemd#17044.
  • Loading branch information
ReneHollander committed Aug 15, 2022
1 parent 38db7a4 commit c8e33c6
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 23 deletions.
13 changes: 13 additions & 0 deletions man/bootctl.xml
Expand Up @@ -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 perferable 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 where there is a redundant array
of 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"/>
Expand Down
78 changes: 55 additions & 23 deletions src/boot/bootctl.c
Expand Up @@ -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;
Expand Down Expand Up @@ -85,19 +91,25 @@ 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);
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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand All @@ -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 },
{}
};

Expand Down Expand Up @@ -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)) {
_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;

Expand Down

0 comments on commit c8e33c6

Please sign in to comment.