Fix `ostree admin kargs edit-in-place` assertion when deployments
authorHuijing Hei <hhei@redhat.com>
Fri, 19 Aug 2022 03:31:46 +0000 (11:31 +0800)
committerHuijing Hei <hhei@redhat.com>
Mon, 29 Aug 2022 03:31:32 +0000 (11:31 +0800)
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
tests/kolainst/destructive/kargs-edit-in-place.sh

index 1112dedf7b8e2ea9eef0e331781e54c35083b473..7b2f1a6fccdc317f454ed9e5aa49cb8269b4a0f0 100644 (file)
@@ -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_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;
+    }
+  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 *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;
+      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;
+      if (!ostree_bootconfig_parser_write_at (new_bootconfig,
+                                              bootconf_dfd, bootconf_name,
+                                              cancellable, error))
+        return FALSE;
+    }
 
   return TRUE;
 }
index 6380ff3340c9a106df001f4986b97e94e373b677..66b78aa16698acb465ce85908858812d33a5bfb4 100755 (executable)
@@ -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