diff --git a/Makefile-tests.am b/Makefile-tests.am index abf61af2d0..4917da8540 100644 --- a/Makefile-tests.am +++ b/Makefile-tests.am @@ -104,6 +104,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-dir-deploy-syslinux.sh \ tests/test-admin-deploy-bootprefix.sh \ tests/test-admin-deploy-composefs.sh \ tests/test-admin-deploy-var.sh \ @@ -112,9 +113,12 @@ _installed_or_uninstalled_test_scripts = \ tests/test-admin-deploy-switch.sh \ tests/test-admin-deploy-etcmerge-cornercases.sh \ tests/test-admin-deploy-uboot.sh \ + tests/test-admin-dir-deploy-uboot.sh \ tests/test-admin-deploy-grub2.sh \ + tests/test-admin-dir-deploy-grub2.sh \ tests/test-admin-deploy-nomerge.sh \ tests/test-admin-deploy-none.sh \ + tests/test-admin-dir-deploy-none.sh \ tests/test-admin-deploy-bootid-gc.sh \ tests/test-admin-deploy-whiteouts.sh \ tests/test-admin-deploy-emptyetc.sh \ diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c index 2d8705d5c8..858be40946 100644 --- a/src/libostree/ostree-sysroot-deploy.c +++ b/src/libostree/ostree-sysroot-deploy.c @@ -2180,6 +2180,56 @@ install_deployment_kernel (OstreeSysroot *sysroot, int new_bootversion, return TRUE; } +/* Determine whether an existing directory implements the semantics described in + * https://uapi-group.org/specifications/specs/boot_loader_specification/#type-1-boot-loader-entry-keys + */ +static gboolean +is_bootconfig_type1_semantics (OstreeSysroot *sysroot, GCancellable *cancellable, GError **error) +{ + struct stat stbuf; + + if (!_ostree_sysroot_ensure_boot_fd (sysroot, error)) + return FALSE; + + if (!glnx_fstatat_allow_noent (sysroot->boot_fd, "loader/entries.srel", &stbuf, + AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + + if (errno == ENOENT) + { + g_debug ("Didn't find loader/entries.srel file"); + return FALSE; + } + else + { + /* Get semantics type by reading loader/entries.srel */ + gsize len; + g_autofree char *type = glnx_file_get_contents_utf8_at ( + sysroot->boot_fd, "loader/entries.srel", &len, cancellable, error); + if (type == NULL) + { + g_debug ("Invalid loader/entries.srel file"); + return FALSE; + } + + /* Remove trailing newline symbol if there is any */ + type[strcspn (type, "\n")] = 0; + + if (g_strcmp0 (type, "type1") == 0) + { + g_debug ("type1 semantics is found in loader/entries.srel file"); + return TRUE; + } + else + { + g_debug ("Unsupported semantics type ('%s') in loader/entries.srel file", type); + return FALSE; + } + } + + return FALSE; +} + /* We generate the symlink on disk, then potentially do a syncfs() to ensure * that it (and everything else we wrote) has hit disk. Only after that do we * rename it into place. @@ -2208,10 +2258,57 @@ prepare_new_bootloader_link (OstreeSysroot *sysroot, int current_bootversion, in return TRUE; } +/* We generate the directory on disk, then potentially do a syncfs() to ensure + * that it (and everything else we wrote) has hit disk. Only after that do we + * rename it into place (via renameat2 RENAME_EXCHANGE). + */ +static gboolean +prepare_new_bootloader_dir (OstreeSysroot *sysroot, int current_bootversion, int new_bootversion, + GCancellable *cancellable, GError **error) +{ + GLNX_AUTO_PREFIX_ERROR ("Preparing bootloader directory", error); + g_assert ((current_bootversion == 0 && new_bootversion == 1) + || (current_bootversion == 1 && new_bootversion == 0)); + + if (!_ostree_sysroot_ensure_boot_fd (sysroot, error)) + return FALSE; + + /* This allows us to support both /boot on a seperate filesystem to / as well + * as on the same filesystem. Allowed to fail with EPERM on ESP/vfat. + */ + if (TEMP_FAILURE_RETRY (symlinkat (".", sysroot->sysroot_fd, "boot/boot")) < 0) + if (errno != EPERM && errno != EEXIST) + return glnx_throw_errno_prefix (error, "symlinkat"); + + /* As the directory gets swapped with glnx_renameat2_exchange, the new bootloader + * deployment needs to first be moved to the 'old' path, as the 'current' one will + * become the older deployment after the exchange. + */ + g_autofree char *loader_new = g_strdup_printf ("loader.%d", new_bootversion); + g_autofree char *loader_old = g_strdup_printf ("loader.%d", current_bootversion); + + /* Tag boot version under an ostree specific file */ + g_autofree char *version_name = g_strdup_printf ("%s/ostree_bootversion", loader_new); + if (!glnx_file_replace_contents_at (sysroot->boot_fd, version_name, (guint8 *)loader_new, + strlen (loader_new), 0, cancellable, error)) + return FALSE; + + /* It is safe to remove older loader version as it wasn't really deployed */ + if (!glnx_shutil_rm_rf_at (sysroot->boot_fd, loader_old, cancellable, error)) + return FALSE; + + /* Rename new deployment to the older path before the exchange */ + if (!glnx_renameat2_noreplace (sysroot->boot_fd, loader_new, sysroot->boot_fd, loader_old)) + return FALSE; + + return TRUE; +} + /* Update the /boot/loader symlink to point to /boot/loader.$new_bootversion */ static gboolean -swap_bootloader (OstreeSysroot *sysroot, OstreeBootloader *bootloader, int current_bootversion, - int new_bootversion, GCancellable *cancellable, GError **error) +swap_bootloader (OstreeSysroot *sysroot, OstreeBootloader *bootloader, gboolean loader_link, + int current_bootversion, int new_bootversion, GCancellable *cancellable, + GError **error) { GLNX_AUTO_PREFIX_ERROR ("Final bootloader swap", error); @@ -2221,12 +2318,22 @@ swap_bootloader (OstreeSysroot *sysroot, OstreeBootloader *bootloader, int curre if (!_ostree_sysroot_ensure_boot_fd (sysroot, error)) return FALSE; - /* The symlink was already written, and we used syncfs() to ensure - * its data is in place. Renaming now should give us atomic semantics; - * see https://bugzilla.gnome.org/show_bug.cgi?id=755595 - */ - if (!glnx_renameat (sysroot->boot_fd, "loader.tmp", sysroot->boot_fd, "loader", error)) - return FALSE; + if (loader_link) + { + /* The symlink was already written, and we used syncfs() to ensure + * its data is in place. Renaming now should give us atomic semantics; + * see https://bugzilla.gnome.org/show_bug.cgi?id=755595 + */ + if (!glnx_renameat (sysroot->boot_fd, "loader.tmp", sysroot->boot_fd, "loader", error)) + return FALSE; + } + else + { + /* New target is currently under the old/current version */ + g_autofree char *new_target = g_strdup_printf ("loader.%d", current_bootversion); + if (glnx_renameat2_exchange (sysroot->boot_fd, new_target, sysroot->boot_fd, "loader") != 0) + return FALSE; + } /* Now we explicitly fsync this directory, even though it * isn't required for atomicity, for two reasons: @@ -2444,13 +2551,57 @@ write_deployments_bootswap (OstreeSysroot *self, GPtrArray *new_deployments, return glnx_prefix_error (error, "Bootloader write config"); } - if (!prepare_new_bootloader_link (self, self->bootversion, new_bootversion, cancellable, error)) + /* Handle when boot/loader is a link (normal deployment) and as a normal directory (e.g. EFI/vfat) + */ + struct stat stbuf; + gboolean loader_link = FALSE; + gboolean force_type1_semantics = is_bootconfig_type1_semantics (self, cancellable, error); + if (!glnx_fstatat_allow_noent (self->sysroot_fd, "boot/loader", &stbuf, AT_SYMLINK_NOFOLLOW, + error)) + return FALSE; + if (errno == ENOENT) + { + /* When there is no loader, check if the fs supports symlink or not */ + if (TEMP_FAILURE_RETRY (symlinkat (".", self->sysroot_fd, "boot/boot")) < 0) + { + if (errno == EPERM) + loader_link = FALSE; + else if (errno != EEXIST) + return glnx_throw_errno_prefix (error, "symlinkat"); + } + else + loader_link = TRUE; + } + else if (S_ISLNK (stbuf.st_mode)) + loader_link = TRUE; + else if (S_ISDIR (stbuf.st_mode)) + loader_link = FALSE; + else return FALSE; + if (force_type1_semantics && loader_link) + return glnx_throw_errno_prefix (error, "type1 semantics, but boot/loader is symlink"); + + if (loader_link) + { + /* Default and when loader is a link is to swap links */ + if (!prepare_new_bootloader_link (self, self->bootversion, new_bootversion, cancellable, + error)) + return FALSE; + } + else + { + /* Handle boot/loader as a directory, and swap with renameat2 RENAME_EXCHANGE */ + if (!prepare_new_bootloader_dir (self, self->bootversion, new_bootversion, cancellable, + error)) + return FALSE; + } + if (!full_system_sync (self, out_syncstats, cancellable, error)) return FALSE; - if (!swap_bootloader (self, bootloader, self->bootversion, new_bootversion, cancellable, error)) + if (!swap_bootloader (self, bootloader, loader_link, self->bootversion, new_bootversion, + cancellable, error)) return FALSE; if (out_subbootdir) diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c index 3968c38fed..31aa9a8844 100644 --- a/src/libostree/ostree-sysroot.c +++ b/src/libostree/ostree-sysroot.c @@ -601,6 +601,9 @@ compare_loader_configs_for_sorting (gconstpointer a_pp, gconstpointer b_pp) return compare_boot_loader_configs (a, b); } +static gboolean read_current_bootversion (OstreeSysroot *self, int *out_bootversion, + GCancellable *cancellable, GError **error); + /* Read all the bootconfigs from `/boot/loader/`. */ gboolean _ostree_sysroot_read_boot_loader_configs (OstreeSysroot *self, int bootversion, @@ -613,7 +616,16 @@ _ostree_sysroot_read_boot_loader_configs (OstreeSysroot *self, int bootversion, g_autoptr (GPtrArray) ret_loader_configs = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref); - g_autofree char *entries_path = g_strdup_printf ("boot/loader.%d/entries", bootversion); + g_autofree char *entries_path = NULL; + int current_version; + if (!read_current_bootversion (self, ¤t_version, cancellable, error)) + return FALSE; + + if (current_version == bootversion) + entries_path = g_strdup ("boot/loader/entries"); + else + entries_path = g_strdup_printf ("boot/loader.%d/entries", bootversion); + gboolean entries_exists; g_auto (GLnxDirFdIterator) dfd_iter = { 0, @@ -660,7 +672,7 @@ _ostree_sysroot_read_boot_loader_configs (OstreeSysroot *self, int bootversion, return TRUE; } -/* Get the bootversion from the `/boot/loader` symlink. */ +/* Get the bootversion from the `/boot/loader` directory or symlink. */ static gboolean read_current_bootversion (OstreeSysroot *self, int *out_bootversion, GCancellable *cancellable, GError **error) @@ -673,24 +685,44 @@ read_current_bootversion (OstreeSysroot *self, int *out_bootversion, GCancellabl return FALSE; if (errno == ENOENT) { - g_debug ("Didn't find $sysroot/boot/loader symlink; assuming bootversion 0"); + g_debug ("Didn't find $sysroot/boot/loader directory or symlink; assuming bootversion 0"); ret_bootversion = 0; } else { - if (!S_ISLNK (stbuf.st_mode)) - return glnx_throw (error, "Not a symbolic link: boot/loader"); - - g_autofree char *target - = glnx_readlinkat_malloc (self->sysroot_fd, "boot/loader", cancellable, error); - if (!target) - return FALSE; - if (g_strcmp0 (target, "loader.0") == 0) - ret_bootversion = 0; - else if (g_strcmp0 (target, "loader.1") == 0) - ret_bootversion = 1; + if (S_ISLNK (stbuf.st_mode)) + { + /* Traditional link, check version by reading link name */ + g_autofree char *target + = glnx_readlinkat_malloc (self->sysroot_fd, "boot/loader", cancellable, error); + if (!target) + return FALSE; + if (g_strcmp0 (target, "loader.0") == 0) + ret_bootversion = 0; + else if (g_strcmp0 (target, "loader.1") == 0) + ret_bootversion = 1; + else + return glnx_throw (error, "Invalid target '%s' in boot/loader", target); + } else - return glnx_throw (error, "Invalid target '%s' in boot/loader", target); + { + /* Loader is a directory, check version by reading ostree_bootversion */ + gsize len; + g_autofree char *version = glnx_file_get_contents_utf8_at ( + self->sysroot_fd, "boot/loader/ostree_bootversion", &len, cancellable, error); + if (version == NULL) + { + g_debug ("Invalid boot/loader/ostree_bootversion, assuming bootversion 0"); + ret_bootversion = 0; + } + else if (g_strcmp0 (version, "loader.0") == 0) + ret_bootversion = 0; + else if (g_strcmp0 (version, "loader.1") == 0) + ret_bootversion = 1; + else + return glnx_throw (error, "Invalid version '%s' in boot/loader/ostree_bootversion", + version); + } } *out_bootversion = ret_bootversion; diff --git a/src/switchroot/ostree-prepare-root.c b/src/switchroot/ostree-prepare-root.c index 8e161be76b..b371d1c9bf 100644 --- a/src/switchroot/ostree-prepare-root.c +++ b/src/switchroot/ostree-prepare-root.c @@ -515,7 +515,7 @@ main (int argc, char *argv[]) * at /boot inside the deployment. */ if (snprintf (srcpath, sizeof (srcpath), "%s/boot/loader", root_mountpoint) < 0) err (EXIT_FAILURE, "failed to assemble /boot/loader path"); - if (lstat (srcpath, &stbuf) == 0 && S_ISLNK (stbuf.st_mode)) + if (lstat (srcpath, &stbuf) == 0 && (S_ISLNK (stbuf.st_mode) || S_ISDIR (stbuf.st_mode))) { if (lstat ("boot", &stbuf) == 0 && S_ISDIR (stbuf.st_mode)) { diff --git a/tests/admin-test.sh b/tests/admin-test.sh index 0c442cfd8b..e96c0851b7 100644 --- a/tests/admin-test.sh +++ b/tests/admin-test.sh @@ -63,6 +63,20 @@ export rev # This initial deployment gets kicked off with some kernel arguments. We also set the initial # timestamp of the deploy directory to the epoch as a regression test. touch -d @0 sysroot/ostree/deploy + +if [ "${folders_instead_symlinks_in_boot}" == "1" ]; then + # Have loader as a directory (simulate ESP-based deployments) + if [ -h sysroot/boot/loader ]; then + loader=`readlink sysroot/boot/loader` + rm -f sysroot/boot/loader + mv sysroot/boot/${loader} sysroot/boot/loader + echo -n ${loader} > sysroot/boot/loader/ostree_bootversion + else + mkdir -p sysroot/boot/loader + echo -n "loader.0" > sysroot/boot/loader/ostree_bootversion + fi +fi + ${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmain/x86_64-runtime new_mtime=$(stat -c '%.Y' sysroot/ostree/deploy) assert_not_streq "${orig_mtime}" "${new_mtime}" @@ -99,7 +113,12 @@ echo "ok nice error for deploy with no stateroot" # Test layout of bootloader config and refs assert_not_has_dir sysroot/boot/loader.0 -assert_has_dir sysroot/boot/loader.1 +if [ "${folders_instead_symlinks_in_boot}" == "1" ]; then + assert_not_has_dir sysroot/boot/loader.1 + assert_file_has_content sysroot/boot/loader/ostree_bootversion 'loader.1' +else + assert_has_dir sysroot/boot/loader.1 +fi assert_has_dir sysroot/ostree/boot.1.1 assert_has_file sysroot/boot/loader/entries/ostree-1.conf assert_file_has_content sysroot/boot/loader/entries/ostree-1.conf 'options.* root=LABEL=MOO' @@ -122,7 +141,12 @@ ${CMD_PREFIX} ostree admin deploy --stateroot=testos testos:testos/buildmain/x86 new_mtime=$(stat -c '%.Y' sysroot/ostree/deploy) assert_not_streq "${orig_mtime}" "${new_mtime}" # Need a new bootversion, sine we now have two deployments -assert_has_dir sysroot/boot/loader.0 +if [ "${folders_instead_symlinks_in_boot}" == "1" ]; then + assert_not_has_dir sysroot/boot/loader.0 + assert_file_has_content sysroot/boot/loader/ostree_bootversion 'loader.0' +else + assert_has_dir sysroot/boot/loader.0 +fi assert_not_has_dir sysroot/boot/loader.1 assert_has_dir sysroot/ostree/boot.0.1 assert_not_has_dir sysroot/ostree/boot.0.0 @@ -140,8 +164,13 @@ echo "ok second deploy" ${CMD_PREFIX} ostree admin deploy --os=testos testos:testos/buildmain/x86_64-runtime # Keep the same bootversion -assert_has_dir sysroot/boot/loader.0 assert_not_has_dir sysroot/boot/loader.1 +if [ "${folders_instead_symlinks_in_boot}" == "1" ]; then + assert_not_has_dir sysroot/boot/loader.0 + assert_file_has_content sysroot/boot/loader/ostree_bootversion 'loader.0' +else + assert_has_dir sysroot/boot/loader.0 +fi # But swap subbootversion assert_has_dir sysroot/ostree/boot.0.0 assert_not_has_dir sysroot/ostree/boot.0.1 @@ -155,7 +184,12 @@ ${CMD_PREFIX} ostree admin os-init otheros ${CMD_PREFIX} ostree admin deploy --os=otheros testos/buildmain/x86_64-runtime assert_not_has_dir sysroot/boot/loader.0 -assert_has_dir sysroot/boot/loader.1 +if [ "${folders_instead_symlinks_in_boot}" == "1" ]; then + assert_not_has_dir sysroot/boot/loader.1 + assert_file_has_content sysroot/boot/loader/ostree_bootversion 'loader.1' +else + assert_has_dir sysroot/boot/loader.1 +fi assert_has_file sysroot/boot/loader/entries/ostree-2.conf assert_has_file sysroot/boot/loader/entries/ostree-3.conf assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.1/etc/os-release 'NAME=TestOS' @@ -167,8 +201,13 @@ validate_bootloader echo "ok independent deploy" ${CMD_PREFIX} ostree admin deploy --retain --os=testos testos:testos/buildmain/x86_64-runtime -assert_has_dir sysroot/boot/loader.0 assert_not_has_dir sysroot/boot/loader.1 +if [ "${folders_instead_symlinks_in_boot}" == "1" ]; then + assert_not_has_dir sysroot/boot/loader.0 + assert_file_has_content sysroot/boot/loader/ostree_bootversion 'loader.0' +else + assert_has_dir sysroot/boot/loader.0 +fi assert_has_file sysroot/boot/loader/entries/ostree-4.conf assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.2/etc/os-release 'NAME=TestOS' assert_has_file sysroot/boot/loader/entries/ostree-2.conf @@ -185,7 +224,12 @@ rm sysroot/ostree/deploy/testos/deploy/${rev}.3/etc/aconfigfile ln -s /ENOENT sysroot/ostree/deploy/testos/deploy/${rev}.3/etc/a-new-broken-symlink ${CMD_PREFIX} ostree admin deploy --retain --os=testos testos:testos/buildmain/x86_64-runtime assert_not_has_dir sysroot/boot/loader.0 -assert_has_dir sysroot/boot/loader.1 +if [ "${folders_instead_symlinks_in_boot}" == "1" ]; then + assert_not_has_dir sysroot/boot/loader.1 + assert_file_has_content sysroot/boot/loader/ostree_bootversion 'loader.1' +else + assert_has_dir sysroot/boot/loader.1 +fi link=sysroot/ostree/deploy/testos/deploy/${rev}.4/etc/a-new-broken-symlink if ! test -L ${link}; then ls -al ${link} @@ -215,8 +259,13 @@ assert_has_file sysroot/boot/loader/entries/ostree-1.conf assert_not_has_file sysroot/boot/loader/entries/ostree-2.conf assert_not_has_file sysroot/boot/loader/entries/ostree-3.conf ${CMD_PREFIX} ostree admin deploy --not-as-default --os=otheros testos:testos/buildmain/x86_64-runtime -assert_has_dir sysroot/boot/loader.0 assert_not_has_dir sysroot/boot/loader.1 +if [ "${folders_instead_symlinks_in_boot}" == "1" ]; then + assert_not_has_dir sysroot/boot/loader.0 + assert_file_has_content sysroot/boot/loader/ostree_bootversion 'loader.0' +else + assert_has_dir sysroot/boot/loader.0 +fi assert_has_file sysroot/boot/loader/entries/ostree-2.conf assert_has_file sysroot/boot/loader/entries/ostree-1.conf ${CMD_PREFIX} ostree admin status @@ -226,7 +275,12 @@ echo "ok deploy --not-as-default" ${CMD_PREFIX} ostree admin deploy --retain-rollback --os=otheros testos:testos/buildmain/x86_64-runtime assert_not_has_dir sysroot/boot/loader.0 -assert_has_dir sysroot/boot/loader.1 +if [ "${folders_instead_symlinks_in_boot}" == "1" ]; then + assert_not_has_dir sysroot/boot/loader.1 + assert_file_has_content sysroot/boot/loader/ostree_bootversion 'loader.1' +else + assert_has_dir sysroot/boot/loader.1 +fi assert_has_file sysroot/boot/loader/entries/ostree-3.conf assert_has_file sysroot/boot/loader/entries/ostree-2.conf assert_has_file sysroot/boot/loader/entries/ostree-1.conf diff --git a/tests/test-admin-deploy-grub2.sh b/tests/test-admin-deploy-grub2.sh index e552cb2048..cebb20bd80 100755 --- a/tests/test-admin-deploy-grub2.sh +++ b/tests/test-admin-deploy-grub2.sh @@ -25,5 +25,6 @@ set -euo pipefail setup_os_repository "archive" "grub2 ostree-grub-generator" extra_admin_tests=0 +folders_instead_symlinks_in_boot=0 . $(dirname $0)/admin-test.sh diff --git a/tests/test-admin-deploy-none.sh b/tests/test-admin-deploy-none.sh index ad79e253fb..7a572d1c5b 100755 --- a/tests/test-admin-deploy-none.sh +++ b/tests/test-admin-deploy-none.sh @@ -25,6 +25,7 @@ set -euo pipefail setup_os_repository "archive" "sysroot.bootloader none" extra_admin_tests=1 +folders_instead_symlinks_in_boot=0 . $(dirname $0)/admin-test.sh diff --git a/tests/test-admin-deploy-syslinux.sh b/tests/test-admin-deploy-syslinux.sh index 3db219893c..14ffe81dbf 100755 --- a/tests/test-admin-deploy-syslinux.sh +++ b/tests/test-admin-deploy-syslinux.sh @@ -25,6 +25,7 @@ set -euo pipefail setup_os_repository "archive" "syslinux" extra_admin_tests=3 +folders_instead_symlinks_in_boot=0 . $(dirname $0)/admin-test.sh diff --git a/tests/test-admin-deploy-uboot.sh b/tests/test-admin-deploy-uboot.sh index 9a4d773b37..b96d23ff89 100755 --- a/tests/test-admin-deploy-uboot.sh +++ b/tests/test-admin-deploy-uboot.sh @@ -28,6 +28,7 @@ modulesdir="usr/lib/modules/${kver}" setup_os_repository "archive" "uboot" ${modulesdir} extra_admin_tests=2 +folders_instead_symlinks_in_boot=0 . $(dirname $0)/admin-test.sh diff --git a/tests/test-admin-dir-deploy-grub2.sh b/tests/test-admin-dir-deploy-grub2.sh new file mode 100755 index 0000000000..bedc507093 --- /dev/null +++ b/tests/test-admin-dir-deploy-grub2.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# +# Copyright (C) 2011,2014 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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, see . + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +# Exports OSTREE_SYSROOT so --sysroot not needed. +setup_os_repository "archive" "grub2 ostree-grub-generator" + +extra_admin_tests=0 +folders_instead_symlinks_in_boot=1 + +. $(dirname $0)/admin-test.sh diff --git a/tests/test-admin-dir-deploy-none.sh b/tests/test-admin-dir-deploy-none.sh new file mode 100755 index 0000000000..06fcb610e1 --- /dev/null +++ b/tests/test-admin-dir-deploy-none.sh @@ -0,0 +1,53 @@ +#!/bin/bash +# +# Copyright (C) 2019 Robert Fairley +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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, see . + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +# Exports OSTREE_SYSROOT so --sysroot not needed. +setup_os_repository "archive" "sysroot.bootloader none" + +extra_admin_tests=1 +folders_instead_symlinks_in_boot=1 + +. $(dirname $0)/admin-test.sh + +# Test that the bootloader configuration "none" generates BLS config snippets. +cd ${test_tmpdir} +rm httpd osdata testos-repo sysroot -rf +setup_os_repository "archive" "sysroot.bootloader none" +${CMD_PREFIX} ostree pull-local --repo=sysroot/ostree/repo --remote testos testos-repo testos/buildmain/x86_64-runtime +# Test that configuring sysroot.bootloader="none" is a workaround for previous +# grub2 bootloader issue (see https://github.com/ostreedev/ostree/issues/1774) +mkdir -p sysroot/boot/grub2 +touch sysroot/boot/grub2/grub.cfg +${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os testos testos/buildmain/x86_64-runtime > out.txt +assert_file_has_content out.txt "Bootloader updated.*" +assert_file_has_content sysroot/boot/loader/entries/ostree-1.conf 'options.* root=LABEL=MOO' +assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/vmlinuz-3.6.0 'a kernel' +assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/.vmlinuz-3.6.0.hmac 'an hmac file' +assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/initramfs-3.6.0.img 'an initramfs' +echo "ok generate bls config on first deployment" + +# TODO: add tests to try setting with an unsupported bootloader config, +# once https://github.com/ostreedev/ostree/issues/1827 is solved. +# The tests should check that the following commands fail: +# ${CMD_PREFIX} ostree --repo=sysroot/ostree/repo config set sysroot.bootloader unsupported_bootloader +# ${CMD_PREFIX} ostree --repo=sysroot/ostree/repo config set sysroot.bootloader "" diff --git a/tests/test-admin-dir-deploy-syslinux.sh b/tests/test-admin-dir-deploy-syslinux.sh new file mode 100755 index 0000000000..9def32c945 --- /dev/null +++ b/tests/test-admin-dir-deploy-syslinux.sh @@ -0,0 +1,71 @@ +#!/bin/bash +# +# Copyright (C) 2011,2014 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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, see . + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +# Exports OSTREE_SYSROOT so --sysroot not needed. +setup_os_repository "archive" "syslinux" + +extra_admin_tests=3 +folders_instead_symlinks_in_boot=1 + +. $(dirname $0)/admin-test.sh + +# Test the legacy dirs +for test_bootdir in "boot" "usr/lib/ostree-boot"; do + cd ${test_tmpdir} + rm httpd osdata testos-repo sysroot -rf + setup_os_repository "archive" "syslinux" $test_bootdir + ${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmain/x86_64-runtime + rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmain/x86_64-runtime) + ${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmain/x86_64-runtime + assert_file_has_content sysroot/boot/loader/entries/ostree-1.conf 'options.* root=LABEL=MOO' + assert_file_has_content sysroot/boot/loader/entries/ostree-1.conf 'options.* quiet' + assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/vmlinuz-3.6.0 'a kernel' + assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/initramfs-3.6.0.img 'an initramfs' + # kernel/initrams should also be in the tree's /boot with the checksum + assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/$test_bootdir/vmlinuz-3.6.0-${bootcsum} 'a kernel' + assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/$test_bootdir/initramfs-3.6.0.img-${bootcsum} 'an initramfs' + assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/etc/os-release 'NAME=TestOS' + assert_file_has_content sysroot/ostree/boot.1/testos/${bootcsum}/0/etc/os-release 'NAME=TestOS' + ${CMD_PREFIX} ostree admin status + validate_bootloader + echo "ok kernel in $test_bootdir" +done + +# And test that legacy overrides /usr/lib/modules +cd ${test_tmpdir} +rm httpd osdata testos-repo sysroot -rf +setup_os_repository "archive" "syslinux" "usr/lib/ostree-boot" +cd osdata +echo "this is a kernel without an initramfs like Fedora 26" > usr/lib/modules/3.6.0/vmlinuz +usrlib_modules_bootcsum=$(cat usr/lib/modules/3.6.0/vmlinuz | sha256sum | cut -f 1 -d ' ') +${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --add-metadata-string version=1.0.9 -b testos/buildmain/x86_64-runtime -s "Build" +cd ${test_tmpdir} +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmain/x86_64-runtime +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmain/x86_64-runtime) +${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmain/x86_64-runtime +assert_file_has_content sysroot/boot/loader/entries/ostree-1.conf 'options.* root=LABEL=MOO' +assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/vmlinuz-3.6.0 'a kernel' +assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/initramfs-3.6.0.img 'an initramfs' +# Note this bootcsum shouldn't be the modules one +assert_not_streq "${bootcsum}" "${usrlib_modules_bootcsum}" +echo "ok kernel in /usr/lib/modules and /usr/lib/ostree-boot" diff --git a/tests/test-admin-dir-deploy-uboot.sh b/tests/test-admin-dir-deploy-uboot.sh new file mode 100755 index 0000000000..5913ce84f8 --- /dev/null +++ b/tests/test-admin-dir-deploy-uboot.sh @@ -0,0 +1,79 @@ +#!/bin/bash +# +# Copyright (C) 2011,2014 Colin Walters +# Copyright (C) 2013 Javier Martinez +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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, see . + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +# Exports OSTREE_SYSROOT so --sysroot not needed. +kver="3.6.0" +modulesdir="usr/lib/modules/${kver}" +setup_os_repository "archive" "uboot" ${modulesdir} + +extra_admin_tests=2 +folders_instead_symlinks_in_boot=1 + +. $(dirname $0)/admin-test.sh + +cd ${test_tmpdir} +# Note this test actually requires a checksum change to /boot, +# because adding the uEnv.txt isn't currently covered by the +# "bootcsum". +os_repository_new_commit "uboot test" "test upgrade multiple kernel args" +mkdir -p osdata/usr/lib/ostree-boot +cat << 'EOF' > osdata/usr/lib/ostree-boot/uEnv.txt +loaduimage=load mmc ${bootpart} ${loadaddr} ${kernel_image} +loadfdt=load mmc ${bootpart} ${fdtaddr} ${bootdir}${fdtfile} +loadramdisk=load mmc ${bootpart} ${rdaddr} ${ramdisk_image} +mmcargs=setenv bootargs $bootargs console=${console} ${optargs} root=${mmcroot} rootfstype=${mmcrootfstype} +mmcboot=run loadramdisk; echo Booting from mmc ....; run mmcargs; bootz ${loadaddr} ${rdaddr} ${fdtaddr} +EOF +${CMD_PREFIX} ostree --repo=testos-repo commit --tree=dir=osdata/ -b testos/buildmain/x86_64-runtime +${CMD_PREFIX} ostree admin upgrade --os=testos +assert_file_has_content sysroot/boot/uEnv.txt "loadfdt=" +assert_file_has_content sysroot/boot/uEnv.txt "kernel_image=" +assert_file_has_content sysroot/boot/uEnv.txt "kernel_image2=" +assert_file_has_content sysroot/boot/uEnv.txt "kernel_image3=" + +echo "ok merging uEnv.txt files" + +cd ${test_tmpdir} +os_repository_new_commit "uboot test" "test with device tree directory" + +devicetree_path=osdata/${modulesdir}/dtb/asoc-board.dtb +devicetree_overlay_path=osdata/${modulesdir}/dtb/overlays/overlay.dtbo + +mkdir -p osdata/${modulesdir}/dtb +echo "a device tree" > ${devicetree_path} +mkdir -p osdata/${modulesdir}/dtb/overlays +echo "a device tree overlay" > ${devicetree_overlay_path} + +bootcsum=$( + (echo "new: a kernel uboot test" && echo "new: an initramfs uboot test" && + cat ${devicetree_path} ${devicetree_overlay_path} ) | + sha256sum | cut -f 1 -d ' ') + +${CMD_PREFIX} ostree --repo=testos-repo commit --tree=dir=osdata/ -b testos/buildmain/x86_64-runtime +${CMD_PREFIX} ostree admin upgrade --os=testos +assert_file_has_content sysroot/boot/uEnv.txt "fdtdir=" +assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/dtb/asoc-board.dtb 'a device tree' +assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/dtb/overlays/overlay.dtbo 'a device tree overlay' + +echo "ok deploying fdtdir"