]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
bootctl: add --install-source=auto|image|host
authorLuca Boccassi <bluca@debian.org>
Sun, 12 Jun 2022 23:21:41 +0000 (00:21 +0100)
committerLuca Boccassi <bluca@debian.org>
Fri, 8 Jul 2022 15:58:51 +0000 (16:58 +0100)
When using --root=/--image= the binaries to install/update will be
picked from the directory/image. Add an option to let the caller
choose.
By default (auto) the image is tried first, and if nothing is found
then the host. The other options allow to strictly try the image
or host and ignore the other.

man/bootctl.xml
shell-completion/bash/bootctl
shell-completion/zsh/_bootctl
src/boot/bootctl.c

index 839fa79efd85a7a5f2063390c333fe610a9a9ff9..1664f68157a2adb0c2d1a39d70cd16484ef68976 100644 (file)
         switch of the same name.</para></listitem>
       </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>
index fd71cffe3f05e50591581323ff7edda4f6197644..0b7cef7871b02490a44a0f376406a5c8fc11c0ef 100644 (file)
@@ -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
index fbd62bc0fd91fa97e8b23d281b3f8fdc2c6def4c..8634e8b9bc06496d1f5de2176b21b6e43ebb0faf 100644 (file)
@@ -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'
index 6cb0f4253935135256827dd1ff0aaf7c9b867bd9..c09c305b3f3f1c042c0cdec7a88b7f3bb3b3f1cd 100644 (file)
@@ -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;
 }