sysroot: Support /boot on root or as seperate filesystem for syslinux and u-boot
authorWilliam Manley <will@stb-tester.com>
Wed, 15 Jul 2020 14:40:14 +0000 (15:40 +0100)
committerWilliam Manley <will@stb-tester.com>
Wed, 15 Jul 2020 19:37:49 +0000 (20:37 +0100)
We use a similar trick to having a `sysroot -> .` symlink on the real root
here to support both /boot on root as well as on a separate filesystem.  No
matter how it's mounted `/boot/xyz` will always refer to the file you'd
expect.

This is nicer than my previous attempts at this because there's no
configuration nor auto-detection required.

src/libostree/ostree-bootloader-syslinux.c
src/libostree/ostree-bootloader-uboot.c
src/libostree/ostree-sysroot-deploy.c
tests/bootloader-entries-crosscheck.py

index 5fb8a1dbd2672e1ab4d68e2c49d9ade9ad2ba917..0055896bd9c04b63be99480ad87953040e460ea5 100644 (file)
@@ -89,15 +89,15 @@ append_config_from_loader_entries (OstreeBootloaderSyslinux  *self,
       val = ostree_bootconfig_parser_get (config, "linux");
       if (!val)
         return glnx_throw (error, "No \"linux\" key in bootloader config");
-      g_ptr_array_add (new_lines, g_strdup_printf ("\tKERNEL %s", val));
+      g_ptr_array_add (new_lines, g_strdup_printf ("\tKERNEL /boot%s", val));
 
       val = ostree_bootconfig_parser_get (config, "initrd");
       if (val)
-        g_ptr_array_add (new_lines, g_strdup_printf ("\tINITRD %s", val));
+        g_ptr_array_add (new_lines, g_strdup_printf ("\tINITRD /boot%s", val));
 
       val = ostree_bootconfig_parser_get (config, "devicetree");
       if (val)
-        g_ptr_array_add (new_lines, g_strdup_printf ("\tDEVICETREE %s", val));
+        g_ptr_array_add (new_lines, g_strdup_printf ("\tDEVICETREE /boot%s", val));
 
       val = ostree_bootconfig_parser_get (config, "options");
       if (val)
@@ -150,10 +150,13 @@ _ostree_bootloader_syslinux_write_config (OstreeBootloader  *bootloader,
           if (kernel_arg == NULL)
             return glnx_throw (error, "No KERNEL argument found after LABEL");
 
-          /* If this is a non-ostree kernel, just emit the lines
-           * we saw.
+          /* If this is a non-ostree kernel, just emit the lines we saw.
+           *
+           * We check for /ostree (without /boot prefix) as well to support
+           * upgrading ostree from <v2020.4.
            */
-          if (!g_str_has_prefix (kernel_arg, "/ostree/"))
+          if (!g_str_has_prefix (kernel_arg, "/ostree/") &&
+              !g_str_has_prefix (kernel_arg, "/boot/ostree/"))
             {
               for (guint i = 0; i < tmp_lines->len; i++)
                 {
index 1e1f0371d7de04b39bff272683a705b26d5c28da..7e23001e1fe7e57f1467fdc5f53cdb10b218e519 100644 (file)
@@ -134,19 +134,19 @@ create_config_from_boot_loader_entries (OstreeBootloaderUboot     *self,
                        "No \"linux\" key in bootloader config");
           return FALSE;
         }
-      g_ptr_array_add (new_lines, g_strdup_printf ("kernel_image%s=%s", index_suffix, val));
+      g_ptr_array_add (new_lines, g_strdup_printf ("kernel_image%s=/boot%s", index_suffix, val));
 
       val = ostree_bootconfig_parser_get (config, "initrd");
       if (val)
-        g_ptr_array_add (new_lines, g_strdup_printf ("ramdisk_image%s=%s", index_suffix, val));
+        g_ptr_array_add (new_lines, g_strdup_printf ("ramdisk_image%s=/boot%s", index_suffix, val));
 
       val = ostree_bootconfig_parser_get (config, "devicetree");
       if (val)
-        g_ptr_array_add (new_lines, g_strdup_printf ("fdt_file%s=%s", index_suffix, val));
+        g_ptr_array_add (new_lines, g_strdup_printf ("fdt_file%s=/boot%s", index_suffix, val));
 
       val = ostree_bootconfig_parser_get (config, "fdtdir");
       if (val)
-        g_ptr_array_add (new_lines, g_strdup_printf ("fdtdir%s=%s", index_suffix, val));
+        g_ptr_array_add (new_lines, g_strdup_printf ("fdtdir%s=/boot%s", index_suffix, val));
 
       val = ostree_bootconfig_parser_get (config, "options");
       if (val)
index cb593020876c7bc5515880f59136761de9c2fc67..ec51ad9a5aefe3945d8f9a2a1fba1b10268c1d32 100644 (file)
@@ -1998,6 +1998,12 @@ prepare_new_bootloader_link (OstreeSysroot  *sysroot,
   g_assert ((current_bootversion == 0 && new_bootversion == 1) ||
             (current_bootversion == 1 && new_bootversion == 0));
 
+  /* This allows us to support both /boot on a seperate filesystem to / as well
+   * as on the same filesystem. */
+  if (TEMP_FAILURE_RETRY (symlinkat (".", sysroot->sysroot_fd, "boot/boot")) < 0)
+    if (errno != EEXIST)
+      return glnx_throw_errno_prefix (error, "symlinkat");
+
   g_autofree char *new_target = g_strdup_printf ("loader.%d", new_bootversion);
 
   /* We shouldn't actually need to replace but it's easier to reuse
index b4cdcbf5b118e1d8df2750d2cb97ddd2b030bcba..605bd080ca41948992616f937af1108aa59bbf77 100755 (executable)
@@ -97,15 +97,32 @@ with open(syslinuxpath) as f:
 if len(entries) != len(syslinux_entries):
     fatal("Found {0} loader entries, but {1} SYSLINUX entries\n".format(len(entries), len(syslinux_entries)))
 
-def assert_matches_key(a, b, key):
+
+def assert_eq(a, b):
+    assert a == b, "%r == %r" % (a, b)
+
+
+def assert_key_same_file(a, b, key):
     aval = a[key]
     bval = b[key]
-    if aval != bval:
-        fatal("Mismatch on {0}: {1} != {2}".format(key, aval, bval))
+    sys.stderr.write("aval: %r\nbval: %r\n" % (aval, bval))
+
+    # Paths in entries are always relative to /boot
+    entry = os.stat(sysroot + "/boot" + aval)
+
+    # Syslinux entries can be relative to /boot (if it's on another filesystem)
+    # or relative to / if /boot is on /.
+    s1 = os.stat(sysroot + bval)
+    s2 = os.stat(sysroot + "/boot" + bval)
+
+    # A symlink ensures that no matter what they point at the same file
+    assert_eq(entry, s1)
+    assert_eq(entry, s2)
+
 
 for i,(entry,syslinuxentry) in enumerate(zip(entries, syslinux_entries)):
-    assert_matches_key(entry, syslinuxentry, 'linux')
-    assert_matches_key(entry, syslinuxentry, 'initrd')
+    assert_key_same_file(entry, syslinuxentry, 'linux')
+    assert_key_same_file(entry, syslinuxentry, 'initrd')
     entry_ostree = get_ostree_option(entry['options'])
     syslinux_ostree = get_ostree_option(syslinuxentry['options'])
     if entry_ostree != syslinux_ostree: