switchroot: Lower config parser to otcore, add unit tests
authorColin Walters <walters@verbum.org>
Fri, 25 Aug 2023 19:54:20 +0000 (15:54 -0400)
committerColin Walters <walters@verbum.org>
Fri, 25 Aug 2023 19:59:34 +0000 (15:59 -0400)
Part of the continuation of unit testing coverage.

Makefile-tests.am
src/libotcore/otcore-prepare-root.c
src/libotcore/otcore.h
src/switchroot/ostree-prepare-root.c
tests/test-otcore.c

index a8683808750e75a1863ea2040ece1ff9279f14a1..e1cea7fe08fd892fcfc9a64c02cb06c98457d202 100644 (file)
@@ -366,7 +366,7 @@ tests_test_bsdiff_CFLAGS = $(TESTS_CFLAGS)
 tests_test_bsdiff_LDADD = libbsdiff.la $(TESTS_LDADD)
 
 tests_test_otcore_CFLAGS = $(AM_CFLAGS) $(OT_INTERNAL_GIO_UNIX_CFLAGS) -I$(srcdir)/src/libotutil -I$(srcdir)/src/libotcore -I$(srcdir)/libglnx
-tests_test_otcore_LDADD = $(OT_INTERNAL_GIO_UNIX_LIBS) libotcore.la libglnx.la
+tests_test_otcore_LDADD = $(OT_INTERNAL_GIO_UNIX_LIBS) libotcore.la libglnx.la libotutil.la
 
 tests_test_checksum_SOURCES = \
        src/libostree/ostree-core.c \
index f3b1a08677350d79388b2c97eaa9a6bd2d7285e2..189c2a1482d294510507627b968de49b45974135 100644 (file)
@@ -106,3 +106,34 @@ otcore_get_ostree_target (const char *cmdline, char **out_target, GError **error
   *out_target = otcore_find_proc_cmdline_key (cmdline, "ostree");
   return TRUE;
 }
+
+// Load a config file; if it doesn't exist, we return an empty configuration.
+// NULL will be returned if we caught an error.
+GKeyFile *
+otcore_load_config (int rootfs_fd, const char *filename, GError **error)
+{
+  // The path to the config file for this binary
+  static const char *const config_roots[] = { "usr/lib", "etc" };
+  g_autoptr (GKeyFile) ret = g_key_file_new ();
+
+  for (guint i = 0; i < G_N_ELEMENTS (config_roots); i++)
+    {
+      glnx_autofd int fd = -1;
+      g_autofree char *path = g_build_filename (config_roots[i], filename, NULL);
+      if (!ot_openat_ignore_enoent (rootfs_fd, path, &fd, error))
+        return NULL;
+      /* If the config file doesn't exist, that's OK */
+      if (fd == -1)
+        continue;
+
+      g_print ("Loading %s\n", path);
+
+      g_autofree char *buf = glnx_fd_readall_utf8 (fd, NULL, NULL, error);
+      if (!buf)
+        return NULL;
+      if (!g_key_file_load_from_data (ret, buf, -1, 0, error))
+        return NULL;
+    }
+
+  return g_steal_pointer (&ret);
+}
index d41758e1c6e2eeeadea513afa65f10e73cbc6700..ba162b8d14e059a984efcc6d64a80cd1232e553c 100644 (file)
@@ -46,6 +46,8 @@ gboolean otcore_validate_ed25519_signature (GBytes *data, GBytes *pubkey, GBytes
 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);
 
+GKeyFile *otcore_load_config (int rootfs, const char *filename, GError **error);
+
 // Our directory with transient state (eventually /run/ostree-booted should be a link to
 // /run/ostree/booted)
 #define OTCORE_RUN_OSTREE "/run/ostree"
index 54a55c1dc45a57a041eb1aaf5c82e34472abe7a7..05cef49260464239b3d31a4d3447374312d26647 100644 (file)
@@ -76,8 +76,6 @@
 #include "ot-keyfile-utils.h"
 #include "otcore.h"
 
-// The path to the config file for this binary
-const char *config_roots[] = { "/usr/lib", "/etc" };
 #define PREPARE_ROOT_CONFIG_PATH "ostree/prepare-root.conf"
 
 // This key is used by default if present in the initramfs to verify
@@ -106,35 +104,6 @@ const char *config_roots[] = { "/usr/lib", "/etc" };
 
 #include "ostree-mount-util.h"
 
-// Load our config file; if it doesn't exist, we return an empty configuration.
-// NULL will be returned if we caught an error.
-static GKeyFile *
-load_config (GError **error)
-{
-  g_autoptr (GKeyFile) ret = g_key_file_new ();
-
-  for (guint i = 0; i < G_N_ELEMENTS (config_roots); i++)
-    {
-      glnx_autofd int fd = -1;
-      g_autofree char *path = g_build_filename (config_roots[i], PREPARE_ROOT_CONFIG_PATH, NULL);
-      if (!ot_openat_ignore_enoent (AT_FDCWD, path, &fd, error))
-        return NULL;
-      /* If the config file doesn't exist, that's OK */
-      if (fd == -1)
-        continue;
-
-      g_print ("Loading %s\n", path);
-
-      g_autofree char *buf = glnx_fd_readall_utf8 (fd, NULL, NULL, error);
-      if (!buf)
-        return NULL;
-      if (!g_key_file_load_from_data (ret, buf, -1, 0, error))
-        return NULL;
-    }
-
-  return g_steal_pointer (&ret);
-}
-
 static bool
 sysroot_is_configured_ro (const char *sysroot)
 {
@@ -350,7 +319,14 @@ main (int argc, char *argv[])
     err (EXIT_FAILURE, "usage: ostree-prepare-root SYSROOT");
   const char *root_arg = argv[1];
 
-  g_autoptr (GKeyFile) config = load_config (&error);
+  // Since several APIs want to operate in terms of file descriptors, let's
+  // open the initramfs now.  Currently this is just used for the config parser.
+  glnx_autofd int initramfs_rootfs_fd = -1;
+  if (!glnx_opendirat (AT_FDCWD, "/", FALSE, &initramfs_rootfs_fd, &error))
+    errx (EXIT_FAILURE, "Failed to open /: %s", error->message);
+
+  g_autoptr (GKeyFile) config
+      = otcore_load_config (initramfs_rootfs_fd, PREPARE_ROOT_CONFIG_PATH, &error);
   if (!config)
     errx (EXIT_FAILURE, "Failed to parse config: %s", error->message);
 
index 03cfb6c8cf9d1ee9443a96a7f1dfb3f9f747c6f7..4af575bf239c45880a63498686da8e526dbd76aa 100644 (file)
@@ -81,6 +81,54 @@ test_prepare_root_cmdline (void)
   free (g_steal_pointer (&target));
 }
 
+static void
+test_prepare_root_config (void)
+{
+  g_autoptr (GError) error = NULL;
+  g_auto (GLnxTmpDir) tmpdir = {
+    0,
+  };
+  g_assert (glnx_mkdtempat (AT_FDCWD, "/tmp/test-XXXXXX", 0777, &tmpdir, &error));
+  g_assert_no_error (error);
+
+  {
+    g_autoptr (GKeyFile) config = NULL;
+    g_auto (GStrv) keys = NULL;
+    config = otcore_load_config (tmpdir.fd, "ostree/someconfig.conf", &error);
+    g_assert (config);
+    keys = g_key_file_get_groups (config, NULL);
+    g_assert (keys && *keys == NULL);
+  }
+
+  g_assert (glnx_shutil_mkdir_p_at (tmpdir.fd, "usr/lib/ostree", 0755, NULL, NULL));
+  g_assert (glnx_file_replace_contents_at (tmpdir.fd, "usr/lib/ostree/someconfig.conf",
+                                           (guint8 *)"[foo]\nbar=baz", -1, 0, NULL, NULL));
+
+  {
+    g_autoptr (GKeyFile) config = NULL;
+    g_auto (GStrv) keys = NULL;
+    config = otcore_load_config (tmpdir.fd, "ostree/someconfig.conf", &error);
+    g_assert (config);
+    keys = g_key_file_get_groups (config, NULL);
+    g_assert (keys);
+    g_assert_cmpstr (*keys, ==, "foo");
+  }
+
+  g_assert (glnx_shutil_mkdir_p_at (tmpdir.fd, "etc/ostree", 0755, NULL, NULL));
+  g_assert (glnx_file_replace_contents_at (tmpdir.fd, "usr/lib/ostree/someconfig.conf",
+                                           (guint8 *)"[test]\nbar=baz", -1, 0, NULL, NULL));
+
+  {
+    g_autoptr (GKeyFile) config = NULL;
+    g_auto (GStrv) keys = NULL;
+    config = otcore_load_config (tmpdir.fd, "ostree/someconfig.conf", &error);
+    g_assert (config);
+    keys = g_key_file_get_groups (config, NULL);
+    g_assert (keys);
+    g_assert_cmpstr (*keys, ==, "test");
+  }
+}
+
 int
 main (int argc, char **argv)
 {
@@ -88,5 +136,6 @@ main (int argc, char **argv)
   otcore_ed25519_init ();
   g_test_add_func ("/ed25519", test_ed25519);
   g_test_add_func ("/prepare-root-cmdline", test_prepare_root_cmdline);
+  g_test_add_func ("/prepare-root-config", test_prepare_root_config);
   return g_test_run ();
 }