From 1a77911e76edbe87b0f425fe0c5d8c08509f898a Mon Sep 17 00:00:00 2001 From: William Manley Date: Wed, 8 Jul 2020 15:24:22 +0100 Subject: [PATCH] sysroot: Support customising /boot on root for syslinux and u-boot This introduces a new config value "sysroot.boot_path_on_disk": > Tell ostree where the bootloader will be looking for the kernel. This is > the location of `/boot` relative to the root of the boot partition. > > This allows explicitly telling ostree that the boot partition is or is > not separate from the root partition. If `/boot` is on root set this to > `/boot`. If it's on seperate partition this should be set to `/`. > > This must be either an absolute path (starting with `/`) or `auto`. > Defaults to `auto`. > > This setting currently only respected by the u-boot and syslinux > bootloaders. This commit is based on an original by Colin Walters (#215), but takes a different tack. #215 attempts to determine automatically whether `/boot` is on root or not, but there are always situations where this isn't possible so I'm adding a config option here so the user can make it explicit. Future commits can add the automatic detection in, but this means that we don't need to be completely general with the auto-detection. --- Makefile-tests.am | 1 + man/ostree.repo-config.xml | 27 +++++++++++ src/libostree/ostree-bootloader-syslinux.c | 23 +++++++-- src/libostree/ostree-bootloader-uboot.c | 17 ++++--- src/libostree/ostree-sysroot-private.h | 3 ++ src/libostree/ostree-sysroot.c | 37 +++++++++++++++ .../test-admin-deploy-syslinux-bootonslash.sh | 47 +++++++++++++++++++ 7 files changed, 145 insertions(+), 10 deletions(-) create mode 100755 tests/test-admin-deploy-syslinux-bootonslash.sh diff --git a/Makefile-tests.am b/Makefile-tests.am index a41793776e..e95c8efb88 100644 --- a/Makefile-tests.am +++ b/Makefile-tests.am @@ -96,6 +96,7 @@ _installed_or_uninstalled_test_scripts = \ tests/test-admin-upgrade-endoflife.sh \ tests/test-admin-upgrade-systemd-update.sh \ tests/test-admin-deploy-syslinux.sh \ + tests/test-admin-deploy-syslinux-bootonslash.sh \ tests/test-admin-deploy-2.sh \ tests/test-admin-deploy-karg.sh \ tests/test-admin-deploy-switch.sh \ diff --git a/man/ostree.repo-config.xml b/man/ostree.repo-config.xml index 2810a8f9ae..e49af8b895 100644 --- a/man/ostree.repo-config.xml +++ b/man/ostree.repo-config.xml @@ -372,6 +372,33 @@ Boston, MA 02111-1307, USA. + + boot_path_on_disk + + + Tell ostree where the bootloader will be looking for the kernel. + This is the location of /boot relative to the + root of the boot partition. + + + This allows explicitly telling ostree that the boot partition is or + is not seperate from the root partition. If + /boot is on root set this to + /boot. If it's on seperate partition this + should be set to /. + + + This must be either an absolute path (starting with + /) or auto. Defaults to + auto. + + + This setting currently only respected by the u-boot and syslinux + bootloaders. + + + + diff --git a/src/libostree/ostree-bootloader-syslinux.c b/src/libostree/ostree-bootloader-syslinux.c index 5fb8a1dbd2..fb8cfaa878 100644 --- a/src/libostree/ostree-bootloader-syslinux.c +++ b/src/libostree/ostree-bootloader-syslinux.c @@ -66,6 +66,7 @@ append_config_from_loader_entries (OstreeBootloaderSyslinux *self, gboolean regenerate_default, int bootversion, GPtrArray *new_lines, + const char *boot_path_on_disk, GCancellable *cancellable, GError **error) { @@ -89,15 +90,22 @@ append_config_from_loader_entries (OstreeBootloaderSyslinux *self, val = ostree_bootconfig_parser_get (config, "linux"); if (!val) return glnx_throw (error, "No \"linux\" key in bootloader config"); - g_ptr_array_add (new_lines, g_strdup_printf ("\tKERNEL %s", val)); + g_autofree gchar *kernel = g_build_path ("/", boot_path_on_disk, val, NULL); + g_ptr_array_add (new_lines, g_strdup_printf ("\tKERNEL %s", kernel)); val = ostree_bootconfig_parser_get (config, "initrd"); if (val) - g_ptr_array_add (new_lines, g_strdup_printf ("\tINITRD %s", val)); + { + g_autofree gchar *initrd = g_build_path ("/", boot_path_on_disk, val, NULL); + g_ptr_array_add (new_lines, g_strdup_printf ("\tINITRD %s", initrd)); + } val = ostree_bootconfig_parser_get (config, "devicetree"); if (val) - g_ptr_array_add (new_lines, g_strdup_printf ("\tDEVICETREE %s", val)); + { + g_autofree gchar *devicetree = g_build_path ("/", boot_path_on_disk, val, NULL); + g_ptr_array_add (new_lines, g_strdup_printf ("\tDEVICETREE %s", devicetree)); + } val = ostree_bootconfig_parser_get (config, "options"); if (val) @@ -130,6 +138,11 @@ _ostree_bootloader_syslinux_write_config (OstreeBootloader *bootloader, g_autoptr(GPtrArray) new_lines = g_ptr_array_new_with_free_func (g_free); g_autoptr(GPtrArray) tmp_lines = g_ptr_array_new_with_free_func (g_free); + g_autofree const char *boot_path_on_disk = _ostree_sysroot_get_boot_path_on_disk ( + self->sysroot, error); + if (boot_path_on_disk == NULL) + return FALSE; + g_autofree char *kernel_arg = NULL; gboolean saw_default = FALSE; gboolean regenerate_default = FALSE; @@ -142,6 +155,7 @@ _ostree_bootloader_syslinux_write_config (OstreeBootloader *bootloader, { const char *line = *iter; gboolean skip = FALSE; + g_autofree char *nonostree_prefix = g_build_path ("/", boot_path_on_disk, "/ostree/", NULL); if (parsing_label && (line == NULL || !g_str_has_prefix (line, "\t"))) @@ -153,7 +167,7 @@ _ostree_bootloader_syslinux_write_config (OstreeBootloader *bootloader, /* If this is a non-ostree kernel, just emit the lines * we saw. */ - if (!g_str_has_prefix (kernel_arg, "/ostree/")) + if (!g_str_has_prefix (kernel_arg, nonostree_prefix)) { for (guint i = 0; i < tmp_lines->len; i++) { @@ -211,6 +225,7 @@ _ostree_bootloader_syslinux_write_config (OstreeBootloader *bootloader, if (!append_config_from_loader_entries (self, regenerate_default, bootversion, new_lines, + boot_path_on_disk, cancellable, error)) return FALSE; diff --git a/src/libostree/ostree-bootloader-uboot.c b/src/libostree/ostree-bootloader-uboot.c index 1e1f0371d7..c133aabc89 100644 --- a/src/libostree/ostree-bootloader-uboot.c +++ b/src/libostree/ostree-bootloader-uboot.c @@ -105,15 +105,20 @@ append_system_uenv (OstreeBootloaderUboot *self, static gboolean create_config_from_boot_loader_entries (OstreeBootloaderUboot *self, - int bootversion, - GPtrArray *new_lines, - GCancellable *cancellable, - GError **error) + int bootversion, + GPtrArray *new_lines, + GCancellable *cancellable, + GError **error) { g_autoptr(GPtrArray) boot_loader_configs = NULL; OstreeBootconfigParser *config; const char *val; + g_autofree const char *boot_path_on_disk = _ostree_sysroot_get_boot_path_on_disk ( + self->sysroot, error); + if (boot_path_on_disk == NULL) + return FALSE; + if (!_ostree_sysroot_read_boot_loader_configs (self->sysroot, bootversion, &boot_loader_configs, cancellable, error)) return FALSE; @@ -134,11 +139,11 @@ create_config_from_boot_loader_entries (OstreeBootloaderUboot *self, "No \"linux\" key in bootloader config"); return FALSE; } - g_ptr_array_add (new_lines, g_strdup_printf ("kernel_image%s=%s", index_suffix, val)); + g_ptr_array_add (new_lines, g_strdup_printf ("kernel_image%s=%s%s", index_suffix, boot_path_on_disk, val)); val = ostree_bootconfig_parser_get (config, "initrd"); if (val) - g_ptr_array_add (new_lines, g_strdup_printf ("ramdisk_image%s=%s", index_suffix, val)); + g_ptr_array_add (new_lines, g_strdup_printf ("ramdisk_image%s=%s%s", index_suffix, boot_path_on_disk, val)); val = ostree_bootconfig_parser_get (config, "devicetree"); if (val) diff --git a/src/libostree/ostree-sysroot-private.h b/src/libostree/ostree-sysroot-private.h index 96670b137b..7916a95de4 100644 --- a/src/libostree/ostree-sysroot-private.h +++ b/src/libostree/ostree-sysroot-private.h @@ -167,4 +167,7 @@ gboolean _ostree_sysroot_cleanup_internal (OstreeSysroot *sysroot, GCancellable *cancellable, GError **error); +char * _ostree_sysroot_get_boot_path_on_disk (OstreeSysroot *sysroot, + GError **error); + G_END_DECLS diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c index 5d32f24d3e..daac9886f0 100644 --- a/src/libostree/ostree-sysroot.c +++ b/src/libostree/ostree-sysroot.c @@ -2140,3 +2140,40 @@ ostree_sysroot_deployment_set_pinned (OstreeSysroot *self, return TRUE; } + +/** + * _ostree_sysroot_get_boot_path_on_disk + * + * We need to provide absolute paths to the bootloader for the location of the + * kernel to boot into, but this needs to be relative to root on the filesystem + * that the kernel is on, rather than relative to root of the root filesystem. + * If boot is on a seperate filesystem to root this will typically return "/", + * otherwise it will typically be "/boot". + */ +char * +_ostree_sysroot_get_boot_path_on_disk (OstreeSysroot *sysroot, GError **error) +{ + GKeyFile * config = ostree_repo_get_config (sysroot->repo); + + g_autofree char * boot_path_on_disk = NULL; + if (!ot_keyfile_get_value_with_default_group_optional (config, "sysroot", + "boot_path_on_disk", "auto", + &boot_path_on_disk, error)) + return NULL; + + if (g_str_equal (boot_path_on_disk, "auto")) + { + /* TODO: Be smarter about working this out automatically */ + g_free (boot_path_on_disk); + boot_path_on_disk = g_strdup ("/"); + } + + if (!boot_path_on_disk || boot_path_on_disk[0] != '/') + { + g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED, "sysroot.boot_path_on_disk " + "must be an absolute path. It is \"%s\"", boot_path_on_disk); + return NULL; + } + + return g_steal_pointer (&boot_path_on_disk); +} diff --git a/tests/test-admin-deploy-syslinux-bootonslash.sh b/tests/test-admin-deploy-syslinux-bootonslash.sh new file mode 100755 index 0000000000..735558f37e --- /dev/null +++ b/tests/test-admin-deploy-syslinux-bootonslash.sh @@ -0,0 +1,47 @@ +#!/bin/bash +# +# Copyright (C) 2016 Colin Walters +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +# Exports OSTREE_SYSROOT so --sysroot not needed. +setup_os_repository "archive-z2" "syslinux" + +echo "1..2" + +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime + +# Override the default and say that /boot is not a partition +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo config set sysroot.boot_path_on_disk /boot +${CMD_PREFIX} ostree admin deploy --verbose --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime + +assert_file_has_content sysroot/boot/syslinux/syslinux.cfg "KERNEL /boot/ostree/testos.*vmlinuz" +assert_file_has_content sysroot/boot/syslinux/syslinux.cfg "INITRD /boot/ostree/testos.*initramfs" + +echo "ok bootonslash" + +${CMD_PREFIX} ostree admin undeploy 0 + +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo config set sysroot.boot_path_on_disk / +${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime +assert_file_has_content sysroot/boot/syslinux/syslinux.cfg "KERNEL /ostree/testos.*vmlinuz" +assert_file_has_content sysroot/boot/syslinux/syslinux.cfg "INITRD /ostree/testos.*initramfs" + +echo "ok bootpartition"