summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/bootctl.xml10
-rw-r--r--shell-completion/bash/bootctl5
-rw-r--r--shell-completion/zsh/_bootctl1
-rw-r--r--src/boot/bootctl.c43
4 files changed, 53 insertions, 6 deletions
diff --git a/man/bootctl.xml b/man/bootctl.xml
index 839fa79efd..1664f68157 100644
--- a/man/bootctl.xml
+++ b/man/bootctl.xml
@@ -259,6 +259,16 @@
</varlistentry>
<varlistentry>
+ <term><option>--install-source=</option></term>
+ <listitem><para>When installing binaries with <option>--root=</option> or
+ <option>--image=</option>, selects where to source them from. Takes one of <literal>auto</literal>
+ (the default), <literal>image</literal> or <literal>host</literal>. With <literal>auto</literal>
+ binaries will be picked from the specified directory or image, and if not found they will be picked
+ from the host. With <literal>image</literal> or <literal>host</literal> no fallback search will be
+ performed if the binaries are not found in the selected source.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>-p</option></term>
<term><option>--print-esp-path</option></term>
<listitem><para>This option modifies the behaviour of <command>status</command>. Only prints the path
diff --git a/shell-completion/bash/bootctl b/shell-completion/bash/bootctl
index fd71cffe3f..0b7cef7871 100644
--- a/shell-completion/bash/bootctl
+++ b/shell-completion/bash/bootctl
@@ -32,7 +32,7 @@ _bootctl() {
local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
local -A OPTS=(
[STANDALONE]='-h --help -p --print-esp-path -x --print-boot-path --version --no-variables --no-pager --graceful'
- [ARG]='--esp-path --boot-path --make-machine-id-directory --root --image'
+ [ARG]='--esp-path --boot-path --make-machine-id-directory --root --image --install-source'
)
if __contains_word "$prev" ${OPTS[ARG]}; then
@@ -52,6 +52,9 @@ _bootctl() {
compopt -o nospace
comps=$( compgen -A file -- "$cur" )
;;
+ --install-source)
+ comps="image host auto"
+ ;;
esac
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
return 0
diff --git a/shell-completion/zsh/_bootctl b/shell-completion/zsh/_bootctl
index fbd62bc0fd..8634e8b9bc 100644
--- a/shell-completion/zsh/_bootctl
+++ b/shell-completion/zsh/_bootctl
@@ -75,4 +75,5 @@ _arguments \
'--graceful[Do not fail when locating ESP or writing fails]' \
'--root=[Operate under the specified directory]:PATH' \
'--image=[Operate on the specified image]:PATH' \
+ '--install-source[Where to pick files when using --root=/--image=]:options:(image host auto)' \
'*::bootctl command:_bootctl_commands'
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index 6cb0f42539..c09c305b3f 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -80,6 +80,11 @@ static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
static bool arg_arch_all = false;
static char *arg_root = NULL;
static char *arg_image = NULL;
+static enum {
+ ARG_INSTALL_SOURCE_IMAGE,
+ ARG_INSTALL_SOURCE_HOST,
+ ARG_INSTALL_SOURCE_AUTO,
+} arg_install_source = ARG_INSTALL_SOURCE_AUTO;
STATIC_DESTRUCTOR_REGISTER(arg_esp_path, freep);
STATIC_DESTRUCTOR_REGISTER(arg_xbootldr_path, freep);
@@ -843,6 +848,7 @@ static int create_subdirs(const char *root, const char * const *subdirs) {
}
static int copy_one_file(const char *esp_path, const char *name, bool force) {
+ char *root = IN_SET(arg_install_source, ARG_INSTALL_SOURCE_AUTO, ARG_INSTALL_SOURCE_IMAGE) ? arg_root : NULL;
_cleanup_free_ char *source_path = NULL, *dest_path = NULL, *p = NULL, *q = NULL;
const char *e;
char *dest_name, *s;
@@ -857,13 +863,16 @@ static int copy_one_file(const char *esp_path, const char *name, bool force) {
if (!p)
return log_oom();
- r = chase_symlinks(p, arg_root, CHASE_PREFIX_ROOT, &source_path, NULL);
+ r = chase_symlinks(p, root, CHASE_PREFIX_ROOT, &source_path, NULL);
+ /* If we had a root directory to try, we didn't find it and we are in auto mode, retry on the host */
+ if (r == -ENOENT && root && arg_install_source == ARG_INSTALL_SOURCE_AUTO)
+ r = chase_symlinks(p, NULL, CHASE_PREFIX_ROOT, &source_path, NULL);
if (r < 0)
return log_error_errno(r,
"Failed to resolve path %s%s%s: %m",
p,
- arg_root ? " under directory " : "",
- arg_root ? arg_root : "");
+ root ? " under directory " : "",
+ root ?: "");
q = path_join("/EFI/systemd/", dest_name);
if (!q)
@@ -899,13 +908,17 @@ static int copy_one_file(const char *esp_path, const char *name, bool force) {
}
static int install_binaries(const char *esp_path, const char *arch, bool force) {
+ char *root = IN_SET(arg_install_source, ARG_INSTALL_SOURCE_AUTO, ARG_INSTALL_SOURCE_IMAGE) ? arg_root : NULL;
_cleanup_closedir_ DIR *d = NULL;
_cleanup_free_ char *path = NULL;
int r;
- r = chase_symlinks_and_opendir(BOOTLIBDIR, arg_root, CHASE_PREFIX_ROOT, &path, &d);
+ r = chase_symlinks_and_opendir(BOOTLIBDIR, root, CHASE_PREFIX_ROOT, &path, &d);
+ /* If we had a root directory to try, we didn't find it and we are in auto mode, retry on the host */
+ if (r == -ENOENT && root && arg_install_source == ARG_INSTALL_SOURCE_AUTO)
+ r = chase_symlinks_and_opendir(BOOTLIBDIR, NULL, CHASE_PREFIX_ROOT, &path, &d);
if (r < 0)
- return log_error_errno(r, "Failed to open boot loader directory %s: %m", BOOTLIBDIR);
+ return log_error_errno(r, "Failed to open boot loader directory %s%s: %m", root ?: "", BOOTLIBDIR);
const char *suffix = strjoina(arch, ".efi");
const char *suffix_signed = strjoina(arch, ".efi.signed");
@@ -1394,6 +1407,8 @@ static int help(int argc, char *argv[], void *userdata) {
" --boot-path=PATH Path to the $BOOT partition\n"
" --root=PATH Operate on an alternate filesystem root\n"
" --image=PATH Operate on disk image as filesystem root\n"
+ " --install-source=auto|image|host\n"
+ " Where to pick files when using --root=/--image=\n"
" -p --print-esp-path Print path to the EFI System Partition\n"
" -x --print-boot-path Print path to the $BOOT partition\n"
" --no-variables Don't touch EFI variables\n"
@@ -1426,6 +1441,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_BOOT_PATH,
ARG_ROOT,
ARG_IMAGE,
+ ARG_INSTALL_SOURCE,
ARG_VERSION,
ARG_NO_VARIABLES,
ARG_NO_PAGER,
@@ -1444,6 +1460,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "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' },
@@ -1499,6 +1516,19 @@ static int parse_argv(int argc, char *argv[]) {
return r;
break;
+ case ARG_INSTALL_SOURCE:
+ if (streq(optarg, "auto"))
+ arg_install_source = ARG_INSTALL_SOURCE_AUTO;
+ else if (streq(optarg, "image"))
+ arg_install_source = ARG_INSTALL_SOURCE_IMAGE;
+ else if (streq(optarg, "host"))
+ arg_install_source = ARG_INSTALL_SOURCE_HOST;
+ else
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Unexpected parameter for --install-source=: %s", optarg);
+
+ break;
+
case 'p':
if (arg_print_dollar_boot_path)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
@@ -1592,6 +1622,9 @@ static int parse_argv(int argc, char *argv[]) {
if (arg_root && arg_image)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Please specify either --root= or --image=, the combination of both is not supported.");
+ if (arg_install_source != ARG_INSTALL_SOURCE_AUTO && !arg_root && !arg_image)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--install-from-host is only supported with --root= or --image=.");
+
return 1;
}