bootctl: add "link" command
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "shared-forward.h"
|
||||
|
||||
int verb_link(int argc, char *argv[], uintptr_t data, void *userdata);
|
||||
|
||||
int vl_method_link(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "bootctl.h"
|
||||
#include "bootctl-cleanup.h"
|
||||
#include "bootctl-install.h"
|
||||
#include "bootctl-link.h"
|
||||
#include "bootctl-random-seed.h"
|
||||
#include "bootctl-reboot-to-firmware.h"
|
||||
#include "bootctl-set-efivar.h"
|
||||
@@ -16,6 +17,7 @@
|
||||
#include "bootctl-uki.h"
|
||||
#include "bootctl-unlink.h"
|
||||
#include "bootctl-util.h"
|
||||
#include "bootspec-util.h"
|
||||
#include "build.h"
|
||||
#include "crypto-util.h"
|
||||
#include "devnum-util.h"
|
||||
@@ -82,6 +84,12 @@ char *arg_private_key = NULL;
|
||||
KeySourceType arg_private_key_source_type = OPENSSL_KEY_SOURCE_FILE;
|
||||
char *arg_private_key_source = NULL;
|
||||
bool arg_oldest = false;
|
||||
uint64_t arg_keep_free = KEEP_FREE_BYTES_DEFAULT;
|
||||
char *arg_entry_title = NULL;
|
||||
char *arg_entry_version = NULL;
|
||||
uint64_t arg_entry_commit = 0;
|
||||
char **arg_extras = NULL;
|
||||
unsigned arg_tries_left = UINT_MAX;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_esp_path, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_xbootldr_path, freep);
|
||||
@@ -95,6 +103,9 @@ STATIC_DESTRUCTOR_REGISTER(arg_certificate, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_certificate_source, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_private_key, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_private_key_source, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_entry_title, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_entry_version, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_extras, strv_freep);
|
||||
|
||||
static const char* const install_source_table[_INSTALL_SOURCE_MAX] = {
|
||||
[INSTALL_SOURCE_IMAGE] = "image",
|
||||
@@ -366,6 +377,9 @@ VERB_SCOPE_NOARG(, verb_list, "list",
|
||||
VERB_SCOPE(, verb_unlink, "unlink", "ID", VERB_ANY, 2, 0,
|
||||
"Remove boot loader entry");
|
||||
|
||||
VERB_SCOPE(, verb_link, "link", "KERNEL", 2, 2, 0,
|
||||
"Create boot loader entry for specified kernel");
|
||||
|
||||
VERB_SCOPE_NOARG(, verb_cleanup, "cleanup",
|
||||
"Remove files in ESP not referenced in any boot entry");
|
||||
|
||||
@@ -641,8 +655,115 @@ static int parse_argv(int argc, char *argv[], char ***ret_args) {
|
||||
return r;
|
||||
|
||||
break;
|
||||
|
||||
OPTION_LONG("keep-free", "BYTES",
|
||||
"How much space to keep free on ESP/XBOOTLDR"):
|
||||
|
||||
if (isempty(opts.arg))
|
||||
arg_keep_free = KEEP_FREE_BYTES_DEFAULT;
|
||||
else {
|
||||
r = parse_size(opts.arg, 1024, &arg_keep_free);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse --keep-free=: %s", opts.arg);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
OPTION_LONG("entry-title", "TITLE",
|
||||
"Selects the entry title for the new boot menu entry"):
|
||||
|
||||
if (isempty(opts.arg)) {
|
||||
arg_entry_title = mfree(arg_entry_title);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!efi_loader_entry_title_valid(opts.arg))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not a valid boot menu entry title: %s", opts.arg);
|
||||
|
||||
r = free_and_strdup_warn(&arg_entry_title, opts.arg);
|
||||
if (r < 0)
|
||||
return r;
|
||||
break;
|
||||
|
||||
OPTION_LONG("entry-version", "VERSION",
|
||||
"Selects the entry version for the new boot menu entry"):
|
||||
if (isempty(opts.arg)) {
|
||||
arg_entry_version = mfree(arg_entry_version);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!version_is_valid_versionspec(opts.arg))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not a valid boot menu entry version: %s", opts.arg);
|
||||
|
||||
r = free_and_strdup_warn(&arg_entry_version, opts.arg);
|
||||
if (r < 0)
|
||||
return r;
|
||||
break;
|
||||
|
||||
OPTION_LONG("entry-commit", "NR",
|
||||
"Selects the entry commit version for the new boot menu entry"): {
|
||||
if (isempty(opts.arg)) {
|
||||
arg_entry_commit = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
uint64_t n;
|
||||
r = safe_atou64(opts.arg, &n);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse --entry-commit= parameter: %s", opts.arg);
|
||||
if (!entry_commit_valid(n))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not a valid entry commit number.");
|
||||
|
||||
arg_entry_commit = n;
|
||||
break;
|
||||
}
|
||||
|
||||
OPTION('X', "extra", "PATH",
|
||||
"Pass extra resource (confext, sysext, credential) to the invoked UKI of the boot menu entry"): {
|
||||
|
||||
if (isempty(opts.arg)) {
|
||||
arg_extras = strv_free(arg_extras);
|
||||
break;
|
||||
}
|
||||
|
||||
_cleanup_free_ char *x = NULL;
|
||||
r = parse_path_argument(opts.arg, /* suppress_root= */ false, &x);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
_cleanup_free_ char *fn = NULL;
|
||||
r = path_extract_filename(x, &fn);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to extract filename from '%s': %m", x);
|
||||
if (!efi_loader_entry_resource_filename_valid(fn))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Extra filename '%s' is not suitable for reference in a boot menu entry.", fn);
|
||||
|
||||
r = strv_consume(&arg_extras, TAKE_PTR(x));
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
strv_uniq(arg_extras);
|
||||
break;
|
||||
}
|
||||
|
||||
OPTION_LONG("tries-left", "NR",
|
||||
"Set boot menu entries tries-left counter to the specified value"): {
|
||||
if (isempty(opts.arg)) {
|
||||
arg_tries_left = UINT_MAX;
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned u;
|
||||
r = safe_atou(opts.arg, &u);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse tries left counter: %s", opts.arg);
|
||||
if (u >= UINT_MAX)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Tries left counter too large, refusing: %u", u);
|
||||
|
||||
arg_tries_left = u;
|
||||
break;
|
||||
}}
|
||||
|
||||
char **args = option_parser_get_args(&opts);
|
||||
|
||||
if (!!arg_print_esp_path + !!arg_print_dollar_boot_path + (arg_print_root_device > 0) + arg_print_loader_path + arg_print_stub_path + arg_print_efi_architecture > 1)
|
||||
@@ -711,6 +832,7 @@ static int vl_server(void) {
|
||||
"io.systemd.BootControl.SetRebootToFirmware", vl_method_set_reboot_to_firmware,
|
||||
"io.systemd.BootControl.GetRebootToFirmware", vl_method_get_reboot_to_firmware,
|
||||
"io.systemd.BootControl.Install", vl_method_install,
|
||||
"io.systemd.BootControl.Link", vl_method_link,
|
||||
"io.systemd.BootControl.Unlink", vl_method_unlink);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to bind Varlink methods: %m");
|
||||
|
||||
@@ -52,6 +52,12 @@ extern char *arg_private_key;
|
||||
extern KeySourceType arg_private_key_source_type;
|
||||
extern char *arg_private_key_source;
|
||||
extern bool arg_oldest;
|
||||
extern uint64_t arg_keep_free;
|
||||
extern char *arg_entry_title;
|
||||
extern char *arg_entry_version;
|
||||
extern uint64_t arg_entry_commit;
|
||||
extern char **arg_extras;
|
||||
extern unsigned arg_tries_left;
|
||||
|
||||
static inline const char* arg_dollar_boot_path(void) {
|
||||
/* $BOOT shall be the XBOOTLDR partition if it exists, and otherwise the ESP */
|
||||
@@ -68,3 +74,7 @@ int acquire_xbootldr(int unprivileged_mode, int *ret_fd, sd_id128_t *ret_uuid, d
|
||||
* 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)
|
||||
|
||||
/* Before we "materialize" a new entry, let's ensure we have this much space free still on the partition, by
|
||||
* default */
|
||||
#define KEEP_FREE_BYTES_DEFAULT (5U * U64_MB)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
bootctl_sources = files(
|
||||
'bootctl.c',
|
||||
'bootctl-install.c',
|
||||
'bootctl-link.c',
|
||||
'bootctl-random-seed.c',
|
||||
'bootctl-reboot-to-firmware.c',
|
||||
'bootctl-set-efivar.c',
|
||||
|
||||
Reference in New Issue
Block a user