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.
This commit is contained in:
Дамјан Георгиевски 2020-10-13 12:25:59 +02:00 committed by Lennart Poettering
parent 558e5654a5
commit c4b843473a
2 changed files with 44 additions and 8 deletions

View file

@ -102,6 +102,17 @@
<listitem><para>Sets the default boot loader entry. Takes a single boot loader entry ID string as
argument. The <option>set-oneshot</option> command will set the default entry only for the next boot,
the <option>set-default</option> will set it persistently for all future boots.</para></listitem>
<listitem><para>Optionally, the boot loader entry ID may be specified as one of: <option>@default</option>,
<option>@oneshot</option> or <option>@current</option>, 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
<varname>LoaderEntryDefault</varname>, <varname>LoaderEntryOneShot</varname> and <varname>LoaderEntrySelected</varname>,
see <ulink url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink> 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.
</para></listitem>
</varlistentry>
</variablelist>

View file

@ -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;
_cleanup_free_ char16_t *target = NULL;
size_t target_size = 0;
encoded = utf8_to_utf16(argv[1], strlen(argv[1]));
if (!encoded)
return log_oom();
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 log_error_errno(r, "Failed to update EFI variable: %m");
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 '%s': %m", name);
}
return 0;