generator: Fixes for Android Boot environment
authorEric Curtin <ecurtin@redhat.com>
Wed, 21 Feb 2024 16:02:08 +0000 (16:02 +0000)
committerEric Curtin <ecurtin@redhat.com>
Wed, 21 Feb 2024 20:54:55 +0000 (20:54 +0000)
In Android Boot environment we do not parse ostree= karg to determine
what directory to boot into, alternatively we do this based on the
androidboot.slot_suffix= karg. But we do set ostree=true karg to denote
that we are indeed booting an ostree environment (required for some
systemd unit files). This change accounts for this approach in the
systemd generator. In this case androidboot.slot_suffix= points you to
/ostree/root.[a|b] and then that points you to the directory to boot
into in /ostree/deploy... Here is what a cmdline may look like in this
type of environment:

androidboot.slot_suffix=_a androidboot.bootdevice=*.ufshc root=PARTLABEL=system_a root=UUID=76a22bf4-f153-4541-b6c7-0332c0dfaeac rw ostree=true loglevel=4 acpi=off console=ttyAMA0 systemd.show_status=auto libahci.ignore_sss=1 slub_debug=FPZ fsck.mode=skip rcupdate.rcu_normal_after_boot=0 rcupdate.rcu_expedited=1

Signed-off-by: Eric Curtin <ecurtin@redhat.com>
src/libostree/ostree-impl-system-generator.c
src/libostree/ostree-sysroot-private.h
src/libostree/ostree-sysroot.c
src/libotcore/otcore-prepare-root.c
src/libotcore/otcore.h
src/switchroot/ostree-prepare-root.c
tests/test-otcore.c

index e51584cda8241b13d5553f610f33b88bc3c59611..bfda2b138f7a567947c5f6169274f3d3211f5bfa 100644 (file)
@@ -128,8 +128,8 @@ require_internal_units (const char *normal_dir, const char *early_dir, const cha
 
 /* Generate var.mount */
 static gboolean
-fstab_generator (const char *ostree_cmdline, const char *normal_dir, const char *early_dir,
-                 const char *late_dir, GError **error)
+fstab_generator (const char *ostree_target, const bool is_aboot, const char *normal_dir,
+                 const char *early_dir, const char *late_dir, GError **error)
 {
 #ifdef HAVE_LIBMOUNT
   /* Not currently cancellable, but define a var in case we care later */
@@ -144,7 +144,8 @@ fstab_generator (const char *ostree_cmdline, const char *normal_dir, const char
    * mounted yet.
    */
   g_autofree char *stateroot = NULL;
-  if (!_ostree_sysroot_parse_bootlink (ostree_cmdline, NULL, &stateroot, NULL, NULL, error))
+  if (!_ostree_sysroot_parse_bootlink (ostree_target, is_aboot, NULL, &stateroot, NULL, NULL,
+                                       error))
     return glnx_prefix_error (error, "Parsing stateroot");
 
   /* Load /etc/fstab if it exists, and look for a /var mount */
@@ -261,17 +262,19 @@ _ostree_impl_system_generator (const char *normal_dir, const char *early_dir, co
   if (!cmdline)
     return glnx_throw (error, "Failed to read /proc/cmdline");
 
-  g_autofree char *ostree_cmdline = otcore_find_proc_cmdline_key (cmdline, "ostree");
-
+  g_autoptr (GError) otcore_get_ostree_target_error = NULL;
+  g_autofree char *ostree_target = NULL;
+  bool is_aboot = false;
   /* This could happen in CoreOS live environments, where we hackily mock
    * the `ostree=` karg for `ostree-prepare-root.service` specifically, but
    * otherwise that karg doesn't exist on the real command-line. */
-  if (!ostree_cmdline)
+  if (!otcore_get_ostree_target (cmdline, &is_aboot, &ostree_target,
+                                 &otcore_get_ostree_target_error))
     return TRUE;
 
   if (!require_internal_units (normal_dir, early_dir, late_dir, error))
     return FALSE;
-  if (!fstab_generator (ostree_cmdline, normal_dir, early_dir, late_dir, error))
+  if (!fstab_generator (ostree_target, is_aboot, normal_dir, early_dir, late_dir, error))
     return FALSE;
 
   return TRUE;
index 297b3273a0df7f9cde7f57a13b4755ac6ace4e47..0e9f15bd1609f1a2544503f1404c599b3621385c 100644 (file)
@@ -19,6 +19,8 @@
 
 #pragma once
 
+#include <stdbool.h>
+
 #include "libglnx.h"
 #include "ostree-bootloader.h"
 #include "ostree.h"
@@ -177,8 +179,9 @@ gboolean _ostree_sysroot_parse_bootdir_name (const char *name, char **out_osname
 gboolean _ostree_sysroot_list_all_boot_directories (OstreeSysroot *self, char ***out_bootdirs,
                                                     GCancellable *cancellable, GError **error);
 
-gboolean _ostree_sysroot_parse_bootlink (const char *bootlink, int *out_entry_bootversion,
-                                         char **out_osname, char **out_bootcsum,
-                                         int *out_treebootserial, GError **error);
+gboolean _ostree_sysroot_parse_bootlink (const char *bootlink, const bool is_aboot,
+                                         int *out_entry_bootversion, char **out_osname,
+                                         char **out_bootcsum, int *out_treebootserial,
+                                         GError **error);
 
 G_END_DECLS
index a19b049b3252f4f497a1de00a4dcc40d1f18f9c2..097feb8b2c7fd0c0185808705d119e4377040651 100644 (file)
@@ -724,24 +724,44 @@ load_origin (OstreeSysroot *self, OstreeDeployment *deployment, GCancellable *ca
 
 // Parse the kernel argument ostree=
 gboolean
-_ostree_sysroot_parse_bootlink (const char *bootlink, int *out_entry_bootversion, char **out_osname,
-                                char **out_bootcsum, int *out_treebootserial, GError **error)
+_ostree_sysroot_parse_bootlink (const char *bootlink, const bool is_aboot,
+                                int *out_entry_bootversion, char **out_osname, char **out_bootcsum,
+                                int *out_treebootserial, GError **error)
 {
   static gsize regex_initialized;
   static GRegex *regex;
+  const char *to_parse = bootlink;
+  g_autofree char *symlink_val = NULL;
+  if (is_aboot)
+    {
+      symlink_val = glnx_readlinkat_malloc (-1, bootlink, NULL, error);
+      if (!symlink_val)
+        return glnx_throw (error, "Failed to read '%s' symlink", bootlink);
+
+      to_parse = symlink_val;
+    }
+
   if (g_once_init_enter (&regex_initialized))
     {
-      regex = g_regex_new ("^/ostree/boot.([01])/([^/]+)/([^/]+)/([0-9]+)$", 0, 0, NULL);
+      regex = g_regex_new (is_aboot ? "^deploy/([^/]+)/"
+                                    : "^/ostree/boot.([01])/([^/]+)/([^/]+)/([0-9]+)$",
+                           0, 0, NULL);
       g_assert (regex);
       g_once_init_leave (&regex_initialized, 1);
     }
 
   g_autoptr (GMatchInfo) match = NULL;
-  if (!g_regex_match (regex, bootlink, 0, &match))
+  if (!g_regex_match (regex, to_parse, 0, &match))
     return glnx_throw (error,
                        "Invalid ostree= argument '%s', expected "
-                       "ostree=/ostree/boot.BOOTVERSION/OSNAME/BOOTCSUM/TREESERIAL",
-                       bootlink);
+                       "ostree=/ostree/boot.BOOTVERSION/OSNAME/BOOTCSUM/TREESERIAL or aboot method",
+                       to_parse);
+
+  if (is_aboot)
+    {
+      *out_osname = g_match_info_fetch (match, 1);
+      return TRUE;
+    }
 
   g_autofree char *bootversion_str = g_match_info_fetch (match, 1);
   g_autofree char *treebootserial_str = g_match_info_fetch (match, 4);
@@ -775,7 +795,10 @@ parse_deployment (OstreeSysroot *self, const char *boot_link, OstreeDeployment *
   g_autofree char *osname = NULL;
   g_autofree char *bootcsum = NULL;
   int treebootserial = -1;
-  if (!_ostree_sysroot_parse_bootlink (boot_link, &entry_boot_version, &osname, &bootcsum,
+
+  // Note is_boot should always be false here, this boot_link is taken from BLS file, not
+  // /proc/cmdline, BLS files are present in aboot images
+  if (!_ostree_sysroot_parse_bootlink (boot_link, false, &entry_boot_version, &osname, &bootcsum,
                                        &treebootserial, error))
     return FALSE;
 
index bb7cf4bec29785e610ca932d99a766ec1d516313..19f481c10e1edf3ab1a1e618d246536017b6aec2 100644 (file)
@@ -75,7 +75,7 @@ otcore_find_proc_cmdline_key (const char *cmdline, const char *key)
 //
 // If invalid data is found, @error will be set.
 gboolean
-otcore_get_ostree_target (const char *cmdline, char **out_target, GError **error)
+otcore_get_ostree_target (const char *cmdline, bool *is_aboot, char **out_target, GError **error)
 {
   g_assert (cmdline);
   g_assert (out_target && *out_target == NULL);
@@ -84,8 +84,10 @@ otcore_get_ostree_target (const char *cmdline, char **out_target, GError **error
 
   // First, handle the Android boot case
   g_autofree char *slot_suffix = otcore_find_proc_cmdline_key (cmdline, "androidboot.slot_suffix");
+  *is_aboot = false;
   if (slot_suffix)
     {
+      *is_aboot = true;
       if (strcmp (slot_suffix, "_a") == 0)
         {
           *out_target = g_strdup (slot_a);
index ab22034397065446eb8606d33fc4e7f4a31451e5..79a10f1568647d4538fd71b80b44b9d20c755572 100644 (file)
@@ -44,7 +44,8 @@ gboolean otcore_validate_ed25519_signature (GBytes *data, GBytes *pubkey, GBytes
                                             bool *out_valid, GError **error);
 
 char *otcore_find_proc_cmdline_key (const char *cmdline, const char *key);
-gboolean otcore_get_ostree_target (const char *cmdline, char **out_target, GError **error);
+gboolean otcore_get_ostree_target (const char *cmdline, bool *is_aboot, char **out_target,
+                                   GError **error);
 
 GKeyFile *otcore_load_config (int rootfs, const char *filename, GError **error);
 
index 34d277a02069b9da8982f9569b4df6a80175b01b..14a98b45b1d79fbdda037b68bcc12d10209a1251 100644 (file)
@@ -124,7 +124,8 @@ resolve_deploy_path (const char *root_mountpoint)
 
   g_autoptr (GError) error = NULL;
   g_autofree char *ostree_target = NULL;
-  if (!otcore_get_ostree_target (kernel_cmdline, &ostree_target, &error))
+  bool is_aboot = false;
+  if (!otcore_get_ostree_target (kernel_cmdline, &is_aboot, &ostree_target, &error))
     errx (EXIT_FAILURE, "Failed to determine ostree target: %s", error->message);
   if (!ostree_target)
     errx (EXIT_FAILURE, "No ostree target found");
index 4af575bf239c45880a63498686da8e526dbd76aa..bc2f5a95bc61b09c9c2a960c3f827d59900e3f46 100644 (file)
@@ -36,46 +36,48 @@ test_prepare_root_cmdline (void)
 {
   g_autoptr (GError) error = NULL;
   g_autofree char *target = NULL;
+  bool is_aboot = false;
 
   static const char *notfound_cases[]
       = { "", "foo", "foo=bar baz  sometest", "xostree foo", "xostree=blah bar", NULL };
   for (const char **iter = notfound_cases; iter && *iter; iter++)
     {
       const char *tcase = *iter;
-      g_assert (otcore_get_ostree_target (tcase, &target, &error));
+      g_assert (otcore_get_ostree_target (tcase, &is_aboot, &target, &error));
       g_assert_no_error (error);
       g_assert (target == NULL);
     }
 
   // Test the default ostree=
-  g_assert (otcore_get_ostree_target ("blah baz=blah ostree=/foo/bar somearg", &target, &error));
+  g_assert (otcore_get_ostree_target ("blah baz=blah ostree=/foo/bar somearg", &is_aboot, &target,
+                                      &error));
   g_assert_no_error (error);
   g_assert_cmpstr (target, ==, "/foo/bar");
   free (g_steal_pointer (&target));
 
   // Test android boot
-  g_assert (otcore_get_ostree_target ("blah baz=blah androidboot.slot_suffix=_b somearg", &target,
-                                      &error));
+  g_assert (otcore_get_ostree_target ("blah baz=blah androidboot.slot_suffix=_b somearg", &is_aboot,
+                                      &target, &error));
   g_assert_no_error (error);
   g_assert_cmpstr (target, ==, "/ostree/root.b");
   free (g_steal_pointer (&target));
 
-  g_assert (otcore_get_ostree_target ("blah baz=blah androidboot.slot_suffix=_a somearg", &target,
-                                      &error));
+  g_assert (otcore_get_ostree_target ("blah baz=blah androidboot.slot_suffix=_a somearg", &is_aboot,
+                                      &target, &error));
   g_assert_no_error (error);
   g_assert_cmpstr (target, ==, "/ostree/root.a");
   free (g_steal_pointer (&target));
 
   // And an expected failure to parse a "c" suffix
-  g_assert (!otcore_get_ostree_target ("blah baz=blah androidboot.slot_suffix=_c somearg", &target,
-                                       &error));
+  g_assert (!otcore_get_ostree_target ("blah baz=blah androidboot.slot_suffix=_c somearg",
+                                       &is_aboot, &target, &error));
   g_assert (error);
   g_assert (target == NULL);
   g_clear_error (&error);
 
   // And non-A/B androidboot
-  g_assert (otcore_get_ostree_target ("blah baz=blah androidboot.somethingelse somearg", &target,
-                                      &error));
+  g_assert (otcore_get_ostree_target ("blah baz=blah androidboot.somethingelse somearg", &is_aboot,
+                                      &target, &error));
   g_assert_no_error (error);
   g_assert_cmpstr (target, ==, "/ostree/root.a");
   free (g_steal_pointer (&target));