Skip to content

Commit

Permalink
Fix ostree admin kargs edit-in-place assertion when deployments
Browse files Browse the repository at this point in the history
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=rw
```
After reboot we get both `foo=bar rw`.

Fix ostreedev#2679
  • Loading branch information
HuijingHei committed Aug 22, 2022
1 parent 1fe550e commit bbf2cc7
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 15 deletions.
94 changes: 80 additions & 14 deletions src/libostree/ostree-sysroot-deploy.c
Original file line number Diff line number Diff line change
Expand Up @@ -3614,25 +3614,91 @@ 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))
{
GLNX_AUTO_PREFIX_ERROR ("Loading staged deployment", error);
if (!self->root_is_ostree_booted)
return TRUE; /* Note early return */

OstreeBootconfigParser *new_bootconfig = ostree_deployment_get_bootconfig (deployment);
ostree_bootconfig_parser_set (new_bootconfig, "options", kargs_str);
g_assert (self->booted_deployment);

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_clear_object (&self->staged_deployment);
g_clear_pointer (&self->staged_deployment_data, g_variant_unref);

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;
/* Read the staged state from disk */
glnx_autofd int fd = -1;
if (!ot_openat_ignore_enoent (AT_FDCWD, _OSTREE_SYSROOT_RUNSTATE_STAGED, &fd, error))
return FALSE;
if (fd != -1)
{
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);

/* Parse it */
g_autoptr(GVariant) target = NULL;
g_autofree char **kargs = NULL;
g_autofree char **overlay_initrds = NULL;
g_variant_dict_lookup (staged_deployment_dict, "target", "@a{sv}", &target);
g_variant_dict_lookup (staged_deployment_dict, "kargs", "^a&s", &kargs);
g_variant_dict_lookup (staged_deployment_dict, "overlay-initrds", "^a&s", &overlay_initrds);
if (target)
{
g_autoptr(OstreeDeployment) staged =
_ostree_sysroot_deserialize_deployment_from_variant (target, error);
if (!staged)
return FALSE;

if (!ostree_bootconfig_parser_write_at (new_bootconfig,
bootconf_dfd, bootconf_name,
g_autoptr(OstreeKernelArgs) kargs = ostree_kernel_args_from_string (kargs_str);
g_auto(GStrv) kargs_strv = ostree_kernel_args_to_strv (kargs);
_ostree_deployment_set_bootconfig_from_kargs (staged, kargs_strv);
if (!load_origin (self, staged, NULL, error))
return FALSE;

_ostree_deployment_set_overlay_initrds (staged, overlay_initrds);

self->staged_deployment = g_steal_pointer (&staged);
self->staged_deployment_data = g_steal_pointer (&staged_deployment_data);
/* We set this flag for ostree_deployment_is_staged() because that API
* doesn't have access to the sysroot, which currently has the
* canonical "staged_deployment" reference.
*/
self->staged_deployment->staged = TRUE;
}
}

if (!glnx_file_replace_contents_at (fd, _OSTREE_SYSROOT_RUNSTATE_STAGED,
g_variant_get_data (self->staged_deployment_data),
g_variant_get_size (self->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;
}
Expand Down
20 changes: 19 additions & 1 deletion tests/kolainst/destructive/kargs-edit-in-place.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,22 @@ set -xeuo pipefail
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`"
echo "ok basic 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=testarg1
assert_file_has_content /boot/loader/entries/ostree-* testarg1
/tmp/autopkgtest-reboot 2
;;
"2")
assert_file_has_content_literal /proc/cmdline somedummykarg=1
assert_file_has_content_literal /proc/cmdline testarg1
;;
*)
fatal "Unexpected AUTOPKGTEST_REBOOT_MARK=${AUTOPKGTEST_REBOOT_MARK}"
;;
esac

echo "ok test with stage: kargs edit-in-place --append-if-missing"

0 comments on commit bbf2cc7

Please sign in to comment.