From 37aa2ac2876ae7fb0f14689aa20394694d97c2dd Mon Sep 17 00:00:00 2001 From: Huijing Hei Date: Fri, 19 Aug 2022 11:31:46 +0800 Subject: [PATCH] Fix `ostree admin kargs edit-in-place` assertion when deployments are pending This is to support pending deployments instead of rasing assertion. For example: ``` $ sudo rpm-ostree kargs --append=foo=bar $ sudo ostree admin kargs edit-in-place --append-if-missing=foobar ``` After reboot we get both `foo=bar foobar`. Fix https://github.com/ostreedev/ostree/issues/2679 --- src/libostree/ostree-sysroot-deploy.c | 64 ++++++++++++++----- .../destructive/kargs-edit-in-place.sh | 20 ++++-- 2 files changed, 63 insertions(+), 21 deletions(-) diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c index 1112dedf..7b2f1a6f 100644 --- a/src/libostree/ostree-sysroot-deploy.c +++ b/src/libostree/ostree-sysroot-deploy.c @@ -3614,25 +3614,55 @@ ostree_sysroot_deployment_set_kargs_in_place (OstreeSysroot *self, if (!_ostree_sysroot_ensure_writable (self, error)) return FALSE; - g_assert (!ostree_deployment_is_staged (deployment)); + // handle staged deployment + if (ostree_deployment_is_staged (deployment)) + { + /* Read the staged state from disk */ + glnx_autofd int fd = -1; + if (!glnx_openat_rdonly (AT_FDCWD, _OSTREE_SYSROOT_RUNSTATE_STAGED, TRUE, &fd, error)) + return FALSE; - OstreeBootconfigParser *new_bootconfig = ostree_deployment_get_bootconfig (deployment); - ostree_bootconfig_parser_set (new_bootconfig, "options", kargs_str); - - g_autofree char *bootconf_name = - g_strdup_printf ("ostree-%d-%s.conf", - self->deployments->len - ostree_deployment_get_index (deployment), - ostree_deployment_get_osname (deployment)); - - g_autofree char *bootconfdir = g_strdup_printf ("loader.%d/entries", self->bootversion); - glnx_autofd int bootconf_dfd = -1; - if (!glnx_opendirat (self->boot_fd, bootconfdir, TRUE, &bootconf_dfd, error)) - return FALSE; - - if (!ostree_bootconfig_parser_write_at (new_bootconfig, - bootconf_dfd, bootconf_name, + g_autoptr(GBytes) contents = ot_fd_readall_or_mmap (fd, 0, error); + if (!contents) + return FALSE; + g_autoptr(GVariant) staged_deployment_data = + g_variant_new_from_bytes ((GVariantType*)"a{sv}", contents, TRUE); + g_autoptr(GVariantDict) staged_deployment_dict = + g_variant_dict_new (staged_deployment_data); + + g_autoptr(OstreeKernelArgs) kargs = ostree_kernel_args_from_string (kargs_str); + g_auto(GStrv) kargs_strv = ostree_kernel_args_to_strv (kargs); + + g_variant_dict_insert (staged_deployment_dict, "kargs", "^a&s", kargs_strv); + g_autoptr(GVariant) new_staged_deployment_data = g_variant_dict_end (staged_deployment_dict); + + if (!glnx_file_replace_contents_at (fd, _OSTREE_SYSROOT_RUNSTATE_STAGED, + g_variant_get_data (new_staged_deployment_data), + g_variant_get_size (new_staged_deployment_data), + GLNX_FILE_REPLACE_NODATASYNC, cancellable, error)) - return FALSE; + return FALSE; + } + else + { + OstreeBootconfigParser *new_bootconfig = ostree_deployment_get_bootconfig (deployment); + ostree_bootconfig_parser_set (new_bootconfig, "options", kargs_str); + + g_autofree char *bootconf_name = + g_strdup_printf ("ostree-%d-%s.conf", + self->deployments->len - ostree_deployment_get_index (deployment), + ostree_deployment_get_osname (deployment)); + + g_autofree char *bootconfdir = g_strdup_printf ("loader.%d/entries", self->bootversion); + glnx_autofd int bootconf_dfd = -1; + if (!glnx_opendirat (self->boot_fd, bootconfdir, TRUE, &bootconf_dfd, error)) + return FALSE; + + if (!ostree_bootconfig_parser_write_at (new_bootconfig, + bootconf_dfd, bootconf_name, + cancellable, error)) + return FALSE; + } return TRUE; } diff --git a/tests/kolainst/destructive/kargs-edit-in-place.sh b/tests/kolainst/destructive/kargs-edit-in-place.sh index 6380ff33..66b78aa1 100755 --- a/tests/kolainst/destructive/kargs-edit-in-place.sh +++ b/tests/kolainst/destructive/kargs-edit-in-place.sh @@ -6,7 +6,19 @@ set -xeuo pipefail . ${KOLA_EXT_DATA}/libinsttest.sh -sudo ostree admin kargs edit-in-place --append-if-missing=testarg -assert_file_has_content /boot/loader/entries/ostree-* testarg - -echo "ok test `kargs edit-in-place --append-if-missing`" +case "${AUTOPKGTEST_REBOOT_MARK:-}" in +"") + sudo rpm-ostree kargs --append=somedummykarg=1 + sudo ostree admin kargs edit-in-place --append-if-missing=testarg + assert_file_has_content /boot/loader/entries/ostree-* testarg + /tmp/autopkgtest-reboot "2" + ;; +"2") + assert_file_has_content_literal /proc/cmdline somedummykarg=1 + assert_file_has_content_literal /proc/cmdline testarg + echo "ok test with stage: kargs edit-in-place --append-if-missing" + ;; +*) + fatal "Unexpected AUTOPKGTEST_REBOOT_MARK=${AUTOPKGTEST_REBOOT_MARK}" + ;; +esac