From c4b843473a75fb38ed5bf54e9d3cfb1cb3719efa Mon Sep 17 00:00:00 2001 From: =?utf8?q?=D0=94=D0=B0=D0=BC=D1=98=D0=B0=D0=BD=20=D0=93=D0=B5=D0=BE?= =?utf8?q?=D1=80=D0=B3=D0=B8=D0=B5=D0=B2=D1=81=D0=BA=D0=B8?= Date: Tue, 13 Oct 2020 12:25:59 +0200 Subject: [PATCH] bootctl: add @current/@oneshot/@default targets to set-default/set-oneshot Using `bootctl set-default @current` will set the default loader entry to the currently booted entry as read from the `LoaderEntrySelected` EFI variable. Also `bootctl set-oneshot @current` will set the oneshot loader entry to the current booted entry. Correspondingly `@default` and `@oneshot` can be used to read from the LoaderEntryDefault and LoaderEntryOneshot EFI variables. --- man/bootctl.xml | 11 +++++++++++ src/boot/bootctl.c | 41 +++++++++++++++++++++++++++++++++-------- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/man/bootctl.xml b/man/bootctl.xml index d908d52d97..479cbb5d92 100644 --- a/man/bootctl.xml +++ b/man/bootctl.xml @@ -102,6 +102,17 @@ Sets the default boot loader entry. Takes a single boot loader entry ID string as argument. The command will set the default entry only for the next boot, the will set it persistently for all future boots. + + Optionally, the boot loader entry ID may be specified as one of: , + or , which correspond to the current default boot loader + entry for all future boots, the current default boot loader entry for the next boot, and the currently booted + boot loader entry. These special IDs are resolved to the current values of the EFI variables + LoaderEntryDefault, LoaderEntryOneShot and LoaderEntrySelected, + see Boot Loader Specification for details. + These special IDs are primarily useful as a quick way to persistently make the currently booted boot loader + entry the default choice, or to upgrade the default boot loader entry for the next boot to the default boot + loader entry for all future boots, but may be used for other operations too. + diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index 0e24f0a499..bb8c7398f0 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -1661,6 +1661,31 @@ static int verb_is_installed(int argc, char *argv[], void *userdata) { return EXIT_SUCCESS; } +static int parse_loader_entry_target_arg(const char *arg1, char16_t **ret_target, size_t *ret_target_size) { + int r; + if (streq(arg1, "@current")) { + r = efi_get_variable(EFI_VENDOR_LOADER, "LoaderEntrySelected", NULL, (void *) ret_target, ret_target_size); + if (r < 0) + return log_error_errno(r, "Failed to get EFI variable 'LoaderEntrySelected': %m"); + } else if (streq(arg1, "@oneshot")) { + r = efi_get_variable(EFI_VENDOR_LOADER, "LoaderEntryOneShot", NULL, (void *) ret_target, ret_target_size); + if (r < 0) + return log_error_errno(r, "Failed to get EFI variable 'LoaderEntryOneShot': %m"); + } else if (streq(arg1, "@default")) { + r = efi_get_variable(EFI_VENDOR_LOADER, "LoaderEntryDefault", NULL, (void *) ret_target, ret_target_size); + if (r < 0) + return log_error_errno(r, "Failed to get EFI variable 'LoaderEntryDefault': %m"); + } else { + char16_t *encoded = NULL; + encoded = utf8_to_utf16(arg1, strlen(arg1)); + if (!encoded) + return log_oom(); + *ret_target = encoded; + *ret_target_size = char16_strlen(encoded) * 2 + 2; + } + return 0; +} + static int verb_set_default(int argc, char *argv[], void *userdata) { const char *name; int r; @@ -1693,17 +1718,17 @@ static int verb_set_default(int argc, char *argv[], void *userdata) { if (isempty(argv[1])) { r = efi_set_variable(EFI_VENDOR_LOADER, name, NULL, 0); if (r < 0 && r != -ENOENT) - return log_error_errno(r, "Failed to remove EFI variale: %m"); + return log_error_errno(r, "Failed to remove EFI variable '%s': %m", name); } else { - _cleanup_free_ char16_t *encoded = NULL; - - encoded = utf8_to_utf16(argv[1], strlen(argv[1])); - if (!encoded) - return log_oom(); + _cleanup_free_ char16_t *target = NULL; + size_t target_size = 0; - r = efi_set_variable(EFI_VENDOR_LOADER, name, encoded, char16_strlen(encoded) * 2 + 2); + r = parse_loader_entry_target_arg(argv[1], &target, &target_size); + if (r < 0) + return r; + r = efi_set_variable(EFI_VENDOR_LOADER, name, target, target_size); if (r < 0) - return log_error_errno(r, "Failed to update EFI variable: %m"); + return log_error_errno(r, "Failed to update EFI variable '%s': %m", name); } return 0; -- 2.25.1