diff options
author | Colin Walters <walters@verbum.org> | 2023-01-05 13:26:22 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-01-05 13:26:22 -0500 |
commit | 15a7ed50c59070e72a3bb1c2299e5a5286513927 (patch) | |
tree | e9d0c5f850c042ae7dacbd5353456ce598bb32bf | |
parent | 139f736f79f890d5a73e85aaad8e9e8d4ffb28f9 (diff) | |
parent | 97117753e3e7e0e715c17d3aabff26563230db96 (diff) | |
download | ostree-15a7ed50c59070e72a3bb1c2299e5a5286513927.tar.gz |
Merge pull request #2793 from ericcurtin/aboot-bootloader-support
bootloader: Add an aboot (Android) bootloader backend
-rw-r--r-- | Makefile-libostree.am | 2 | ||||
-rw-r--r-- | rust-bindings/sys/src/lib.rs | 8 | ||||
-rw-r--r-- | src/libostree/ostree-bootloader-aboot.c | 227 | ||||
-rw-r--r-- | src/libostree/ostree-bootloader-aboot.h | 33 | ||||
-rw-r--r-- | src/libostree/ostree-repo-private.h | 2 | ||||
-rw-r--r-- | src/libostree/ostree-sysroot-deploy.c | 58 | ||||
-rw-r--r-- | src/libostree/ostree-sysroot.c | 3 |
7 files changed, 333 insertions, 0 deletions
diff --git a/Makefile-libostree.am b/Makefile-libostree.am index cf54d2b0..4b8a46f5 100644 --- a/Makefile-libostree.am +++ b/Makefile-libostree.am @@ -111,6 +111,8 @@ libostree_1_la_SOURCES = \ src/libostree/ostree-deployment.c \ src/libostree/ostree-bootloader.h \ src/libostree/ostree-bootloader.c \ + src/libostree/ostree-bootloader-aboot.h \ + src/libostree/ostree-bootloader-aboot.c \ src/libostree/ostree-bootloader-grub2.h \ src/libostree/ostree-bootloader-grub2.c \ src/libostree/ostree-bootloader-zipl.h \ diff --git a/rust-bindings/sys/src/lib.rs b/rust-bindings/sys/src/lib.rs index f71a18de..9c270d3d 100644 --- a/rust-bindings/sys/src/lib.rs +++ b/rust-bindings/sys/src/lib.rs @@ -334,6 +334,14 @@ pub struct _OstreeBootloaderSyslinux { pub type OstreeBootloaderSyslinux = *mut _OstreeBootloaderSyslinux; #[repr(C)] +pub struct _OstreeBootloaderAboot { + _data: [u8; 0], + _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>, +} + +pub type OstreeBootloaderAboot = *mut _OstreeBootloaderAboot; + +#[repr(C)] pub struct _OstreeBootloaderUboot { _data: [u8; 0], _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>, diff --git a/src/libostree/ostree-bootloader-aboot.c b/src/libostree/ostree-bootloader-aboot.c new file mode 100644 index 00000000..9370aa6e --- /dev/null +++ b/src/libostree/ostree-bootloader-aboot.c @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2022 Eric Curtin <ericcurtin17@gmail.com> + * + * This program 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 licence 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, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include "ostree-sysroot-private.h" +#include "ostree-bootloader-aboot.h" +#include "ostree-deployment-private.h" +#include "ostree-libarchive-private.h" +#include "otutil.h" +#include <sys/mount.h> + +#include <string.h> + +/* This is specific to aboot and zipl today, but in the future we could also + * use it for the grub2-mkconfig case. + */ +static const char aboot_requires_execute_path[] = "boot/ostree-bootloader-update.stamp"; + +struct _OstreeBootloaderAboot +{ + GObject parent_instance; + + OstreeSysroot *sysroot; +}; + +typedef GObjectClass OstreeBootloaderAbootClass; +static void _ostree_bootloader_aboot_bootloader_iface_init (OstreeBootloaderInterface *iface); +G_DEFINE_TYPE_WITH_CODE (OstreeBootloaderAboot, _ostree_bootloader_aboot, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (OSTREE_TYPE_BOOTLOADER, _ostree_bootloader_aboot_bootloader_iface_init)); + +static gboolean +_ostree_bootloader_aboot_query (OstreeBootloader *bootloader, + gboolean *out_is_active, + GCancellable *cancellable, + GError **error) +{ + /* We don't auto-detect this one; should be explicitly chosen right now. + * see also https://github.com/coreos/coreos-assembler/pull/849 + */ + *out_is_active = FALSE; + return TRUE; +} + +static const char * +_ostree_bootloader_aboot_get_name (OstreeBootloader *bootloader) +{ + return "aboot"; +} + +static gboolean +_ostree_bootloader_aboot_write_config (OstreeBootloader *bootloader, + int bootversion, + GPtrArray *new_deployments, + GCancellable *cancellable, + GError **error) +{ + OstreeBootloaderAboot *self = OSTREE_BOOTLOADER_ABOOT (bootloader); + + /* Write our stamp file */ + if (!glnx_file_replace_contents_at (self->sysroot->sysroot_fd, aboot_requires_execute_path, + (guint8*)"", 0, GLNX_FILE_REPLACE_NODATASYNC, + cancellable, error)) + return FALSE; + + return TRUE; +} + +static gboolean +_ostree_aboot_get_bls_config (OstreeBootloaderAboot *self, + int bootversion, + gchar **aboot, + gchar **abootcfg, + gchar **version, + gchar **vmlinuz, + gchar **initramfs, + gchar **options, + GCancellable *cancellable, + GError **error) +{ + g_autoptr (GPtrArray) configs = NULL; + if ( !_ostree_sysroot_read_boot_loader_configs (self->sysroot, bootversion, &configs, cancellable, error)) + return glnx_prefix_error (error, "aboot: loading bls configs"); + + if (!configs || configs->len == 0) + return glnx_throw (error, "aboot: no bls config"); + + OstreeBootconfigParser *parser = (OstreeBootconfigParser *) g_ptr_array_index (configs, 0); + const gchar *val = NULL; + + val = ostree_bootconfig_parser_get (parser, "aboot"); + if (!val) { + return glnx_throw (error, "aboot: no \"aboot\" key in bootloader config"); + } + *aboot = g_strdup(val); + + val = ostree_bootconfig_parser_get (parser, "abootcfg"); + if (!val) { + return glnx_throw (error, "aboot: no \"abootcfg\" key in bootloader config"); + } + *abootcfg = g_strdup(val); + + val = ostree_bootconfig_parser_get (parser, "version"); + if (!val) + return glnx_throw (error, "aboot: no \"version\" key in bootloader config"); + *version = g_strdup(val); + + val = ostree_bootconfig_parser_get (parser, "linux"); + if (!val) + return glnx_throw (error, "aboot: no \"linux\" key in bootloader config"); + *vmlinuz = g_build_filename ("/boot", val, NULL); + + val = ostree_bootconfig_parser_get (parser, "initrd"); + if (!val) + return glnx_throw (error, "aboot: no \"initrd\" key in bootloader config"); + *initramfs = g_build_filename ("/boot", val, NULL); + + val = ostree_bootconfig_parser_get (parser, "options"); + if (!val) + return glnx_throw (error, "aboot: no \"options\" key in bootloader config"); + *options = g_strdup(val); + + return TRUE; +} + +static gboolean +_ostree_bootloader_aboot_post_bls_sync (OstreeBootloader *bootloader, + int bootversion, + GCancellable *cancellable, + GError **error) +{ + OstreeBootloaderAboot *self = OSTREE_BOOTLOADER_ABOOT (bootloader); + + /* Note that unlike the grub2-mkconfig backend, we make no attempt to + * chroot(). + */ + // g_assert (self->sysroot->booted_deployment); + + if (!glnx_fstatat_allow_noent (self->sysroot->sysroot_fd, aboot_requires_execute_path, NULL, 0, error)) + return FALSE; + + /* If there's no stamp file, nothing to do */ + if (errno == ENOENT) + return TRUE; + + g_autofree gchar* aboot = NULL; + g_autofree gchar* abootcfg = NULL; + g_autofree gchar* version = NULL; + g_autofree gchar* vmlinuz = NULL; + g_autofree gchar* initramfs = NULL; + g_autofree gchar* options = NULL; + if (!_ostree_aboot_get_bls_config (self, bootversion, &aboot, &abootcfg, &version, &vmlinuz, &initramfs, &options, cancellable, error)) + return FALSE; + + g_autofree char *path_str = g_file_get_path(self->sysroot->path); + + const char *const aboot_argv[] = {"aboot-deploy", "-r", path_str, "-c", abootcfg, aboot, NULL}; + int estatus; + if (!g_spawn_sync (NULL, (char**)aboot_argv, NULL, G_SPAWN_SEARCH_PATH, + NULL, NULL, NULL, NULL, &estatus, error)) { + return FALSE; + } + + if (!g_spawn_check_exit_status (estatus, error)) { + return FALSE; + } + + if (!glnx_unlinkat (self->sysroot->sysroot_fd, aboot_requires_execute_path, 0, error)) { + return FALSE; + } + + return TRUE; +} + +static void +_ostree_bootloader_aboot_finalize (GObject *object) +{ + OstreeBootloaderAboot *self = OSTREE_BOOTLOADER_ABOOT (object); + + g_clear_object (&self->sysroot); + + G_OBJECT_CLASS (_ostree_bootloader_aboot_parent_class)->finalize (object); +} + +void +_ostree_bootloader_aboot_init (OstreeBootloaderAboot *self) +{ +} + +static void +_ostree_bootloader_aboot_bootloader_iface_init (OstreeBootloaderInterface *iface) +{ + iface->query = _ostree_bootloader_aboot_query; + iface->get_name = _ostree_bootloader_aboot_get_name; + iface->write_config = _ostree_bootloader_aboot_write_config; + iface->post_bls_sync = _ostree_bootloader_aboot_post_bls_sync; +} + +void +_ostree_bootloader_aboot_class_init (OstreeBootloaderAbootClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->finalize = _ostree_bootloader_aboot_finalize; +} + +OstreeBootloaderAboot * +_ostree_bootloader_aboot_new (OstreeSysroot *sysroot) +{ + OstreeBootloaderAboot *self = g_object_new (OSTREE_TYPE_BOOTLOADER_ABOOT, NULL); + self->sysroot = g_object_ref (sysroot); + return self; +} diff --git a/src/libostree/ostree-bootloader-aboot.h b/src/libostree/ostree-bootloader-aboot.h new file mode 100644 index 00000000..f05457da --- /dev/null +++ b/src/libostree/ostree-bootloader-aboot.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2022 Eric Curtin <ericcurtin17@gmail.com> + * + * This program 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 licence 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, see <https://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "ostree-bootloader.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_BOOTLOADER_ABOOT (_ostree_bootloader_aboot_get_type ()) +#define OSTREE_BOOTLOADER_ABOOT(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), OSTREE_TYPE_BOOTLOADER_ABOOT, OstreeBootloaderAboot)) +#define OSTREE_IS_BOOTLOADER_ABOOT(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), OSTREE_TYPE_BOOTLOADER_ABOOT)) + +typedef struct _OstreeBootloaderAboot OstreeBootloaderAboot; + +GType _ostree_bootloader_aboot_get_type (void) G_GNUC_CONST; + +OstreeBootloaderAboot * _ostree_bootloader_aboot_new (OstreeSysroot *sysroot); +G_END_DECLS diff --git a/src/libostree/ostree-repo-private.h b/src/libostree/ostree-repo-private.h index 0d33f7c2..18e0199e 100644 --- a/src/libostree/ostree-repo-private.h +++ b/src/libostree/ostree-repo-private.h @@ -124,6 +124,7 @@ typedef enum { CFG_SYSROOT_BOOTLOADER_OPT_SYSLINUX, CFG_SYSROOT_BOOTLOADER_OPT_UBOOT, CFG_SYSROOT_BOOTLOADER_OPT_ZIPL, + CFG_SYSROOT_BOOTLOADER_OPT_ABOOT, /* Non-exhaustive */ } OstreeCfgSysrootBootloaderOpt; @@ -135,6 +136,7 @@ static const char* const CFG_SYSROOT_BOOTLOADER_OPTS_STR[] = { "syslinux", "uboot", "zipl", + "aboot", NULL, }; diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c index 482124e2..7554e56c 100644 --- a/src/libostree/ostree-sysroot-deploy.c +++ b/src/libostree/ostree-sysroot-deploy.c @@ -992,6 +992,8 @@ typedef struct { char *initramfs_namever; char *devicetree_srcpath; char *devicetree_namever; + char *aboot_srcpath; + char *aboot_namever; char *bootcsum; } OstreeKernelLayout; static void @@ -1006,6 +1008,8 @@ _ostree_kernel_layout_free (OstreeKernelLayout *layout) g_free (layout->initramfs_namever); g_free (layout->devicetree_srcpath); g_free (layout->devicetree_namever); + g_free (layout->aboot_srcpath); + g_free (layout->aboot_namever); g_free (layout->bootcsum); g_free (layout); } @@ -1131,6 +1135,21 @@ get_kernel_from_tree_usrlib_modules (OstreeSysroot *sysroot, g_clear_object (&in); glnx_close_fd (&fd); + /* look for a aboot.img file. */ + if (!ot_openat_ignore_enoent (ret_layout->boot_dfd, "aboot.img", &fd, error)) + return FALSE; + + if (fd != -1) + { + ret_layout->aboot_srcpath = g_strdup ("aboot.img"); + ret_layout->aboot_namever = g_strdup_printf ("aboot-%s.img", kver); + } + glnx_close_fd (&fd); + + /* look for a aboot.cfg file. */ + if (!ot_openat_ignore_enoent (ret_layout->boot_dfd, "aboot.cfg", &fd, error)) + return FALSE; + /* Testing aid for https://github.com/ostreedev/ostree/issues/2154 */ const gboolean no_dtb = (sysroot->debug_flags & OSTREE_SYSROOT_DEBUG_TEST_NO_DTB) > 0; if (!no_dtb) @@ -1923,6 +1942,21 @@ install_deployment_kernel (OstreeSysroot *sysroot, } } + if (kernel_layout->aboot_srcpath) + { + g_assert (kernel_layout->aboot_namever); + if (!glnx_fstatat_allow_noent (bootcsum_dfd, kernel_layout->aboot_namever, &stbuf, 0, error)) + return FALSE; + + if (errno == ENOENT) + { + if (!install_into_boot (repo, sepolicy, kernel_layout->boot_dfd, kernel_layout->aboot_srcpath, + bootcsum_dfd, kernel_layout->aboot_namever, + cancellable, error)) + return FALSE; + } + } + g_autoptr(GPtrArray) overlay_initrds = NULL; for (char **it = _ostree_deployment_get_overlay_initrds (deployment); it && *it; it++) { @@ -2059,6 +2093,30 @@ install_deployment_kernel (OstreeSysroot *sysroot, ostree_kernel_args_replace_take (kargs, g_steal_pointer (&prepare_root_arg)); } + const char* aboot_fn = NULL; + if (kernel_layout->aboot_namever) + { + aboot_fn = kernel_layout->aboot_namever; + } + else if (kernel_layout->aboot_srcpath) + { + aboot_fn = kernel_layout->aboot_srcpath; + } + + if (aboot_fn) + { + g_autofree char * aboot_relpath = g_strconcat ("/", bootcsumdir, "/", aboot_fn, NULL); + ostree_bootconfig_parser_set (bootconfig, "aboot", aboot_relpath); + } + else + { + g_autofree char * aboot_relpath = g_strconcat ("/", deployment_dirpath, "/usr/lib/ostree-boot/aboot.img", NULL); + ostree_bootconfig_parser_set (bootconfig, "aboot", aboot_relpath); + } + + g_autofree char * abootcfg_relpath = g_strconcat ("/", deployment_dirpath, "/usr/lib/ostree-boot/aboot.cfg", NULL); + ostree_bootconfig_parser_set (bootconfig, "abootcfg", abootcfg_relpath); + if (kernel_layout->devicetree_namever) { g_autofree char * dt_boot_relpath = g_strconcat ("/", bootcsumdir, "/", kernel_layout->devicetree_namever, NULL); diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c index 4c63a657..63d79b41 100644 --- a/src/libostree/ostree-sysroot.c +++ b/src/libostree/ostree-sysroot.c @@ -32,6 +32,7 @@ #include "ostree-sepolicy-private.h" #include "ostree-sysroot-private.h" #include "ostree-deployment-private.h" +#include "ostree-bootloader-aboot.h" #include "ostree-bootloader-uboot.h" #include "ostree-bootloader-syslinux.h" #include "ostree-bootloader-grub2.h" @@ -1475,6 +1476,8 @@ _ostree_sysroot_new_bootloader_by_type ( return (OstreeBootloader*) _ostree_bootloader_grub2_new (sysroot); case CFG_SYSROOT_BOOTLOADER_OPT_SYSLINUX: return (OstreeBootloader*) _ostree_bootloader_syslinux_new (sysroot); + case CFG_SYSROOT_BOOTLOADER_OPT_ABOOT: + return (OstreeBootloader*) _ostree_bootloader_aboot_new (sysroot); case CFG_SYSROOT_BOOTLOADER_OPT_UBOOT: return (OstreeBootloader*) _ostree_bootloader_uboot_new (sysroot); case CFG_SYSROOT_BOOTLOADER_OPT_ZIPL: |