From 61b89963f4423050536c370eebc228ce8c7d81a1 Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Thu, 10 Dec 2020 20:35:54 +0000
Subject: [PATCH] runtime: Factor out function to collect glibc-related files

Signed-off-by: Simon McVittie <smcv@collabora.com>
---
 pressure-vessel/runtime.c | 218 +++++++++++++++++++++-----------------
 1 file changed, 119 insertions(+), 99 deletions(-)

diff --git a/pressure-vessel/runtime.c b/pressure-vessel/runtime.c
index 333abb1e2..17c4fc371 100644
--- a/pressure-vessel/runtime.c
+++ b/pressure-vessel/runtime.c
@@ -2834,6 +2834,120 @@ pv_runtime_collect_graphics_libraries (PvRuntime *self,
   return pv_bwrap_run_sync (temp_bwrap, NULL, error);
 }
 
+static gboolean
+pv_runtime_collect_libc_family (PvRuntime *self,
+                                RuntimeArchitecture *arch,
+                                FlatpakBwrap *bwrap,
+                                const char *libc,
+                                const char *ld_so_in_runtime,
+                                const char *provider_in_container_namespace_guarded,
+                                GHashTable *gconv_in_provider,
+                                GError **error)
+{
+  g_autoptr(FlatpakBwrap) temp_bwrap = NULL;
+  g_autofree char *libc_target = NULL;
+
+  if (!pv_runtime_take_ld_so_from_provider (self, arch,
+                                            ld_so_in_runtime,
+                                            bwrap, error))
+    return FALSE;
+
+  /* Collect miscellaneous libraries that libc might dlopen. */
+  temp_bwrap = pv_runtime_get_capsule_capture_libs (self, arch);
+  flatpak_bwrap_add_args (temp_bwrap,
+                          "--dest", arch->libdir_in_current_namespace,
+                          "if-exists:libidn2.so.0",
+                          "if-exists:even-if-older:soname-match:libnss_compat.so.*",
+                          "if-exists:even-if-older:soname-match:libnss_db.so.*",
+                          "if-exists:even-if-older:soname-match:libnss_dns.so.*",
+                          "if-exists:even-if-older:soname-match:libnss_files.so.*",
+                          NULL);
+  flatpak_bwrap_finish (temp_bwrap);
+
+  if (!pv_bwrap_run_sync (temp_bwrap, NULL, error))
+    return FALSE;
+
+  g_clear_pointer (&temp_bwrap, flatpak_bwrap_free);
+
+  libc_target = glnx_readlinkat_malloc (-1, libc, NULL, NULL);
+  if (libc_target != NULL)
+    {
+      g_autofree gchar *dir = NULL;
+      g_autofree gchar *gconv_dir_in_provider = NULL;
+      gboolean found = FALSE;
+
+      dir = g_path_get_dirname (libc_target);
+
+      if (g_str_has_prefix (dir, provider_in_container_namespace_guarded))
+        memmove (dir,
+                 dir + strlen (self->provider_in_container_namespace),
+                 strlen (dir) - strlen (self->provider_in_container_namespace) + 1);
+
+      /* We are assuming that in the glibc "Makeconfig", $(libdir) was the same as
+       * $(slibdir) (this is the upstream default) or the same as "/usr$(slibdir)"
+       * (like in Debian without the mergerd /usr). We also assume that $(gconvdir)
+       * had its default value "$(libdir)/gconv".
+       * We check /usr first because otherwise, if the host is merged-/usr and the
+       * container is not, we might end up binding /lib instead of /usr/lib
+       * and that could cause issues. */
+      if (g_str_has_prefix (dir, "/usr/"))
+        memmove (dir, dir + strlen ("/usr"), strlen (dir) - strlen ("/usr") + 1);
+
+      gconv_dir_in_provider = g_build_filename ("/usr", dir, "gconv", NULL);
+
+      if (_srt_file_test_in_sysroot (self->provider_in_current_namespace,
+                                     -1,
+                                     gconv_dir_in_provider,
+                                     G_FILE_TEST_IS_DIR))
+        {
+          g_hash_table_add (gconv_in_provider, g_steal_pointer (&gconv_dir_in_provider));
+          found = TRUE;
+        }
+
+      if (!found)
+        {
+          /* Try again without hwcaps subdirectories.
+           * For example, libc6-i386 on SteamOS 2 'brewmaster'
+           * contains /lib/i386-linux-gnu/i686/cmov/libc.so.6,
+           * for which we want gconv modules from
+           * /usr/lib/i386-linux-gnu/gconv, not from
+           * /usr/lib/i386-linux-gnu/i686/cmov/gconv. */
+          while (g_str_has_suffix (dir, "/cmov") ||
+                 g_str_has_suffix (dir, "/i686") ||
+                 g_str_has_suffix (dir, "/sse2") ||
+                 g_str_has_suffix (dir, "/tls") ||
+                 g_str_has_suffix (dir, "/x86_64"))
+            {
+              char *slash = strrchr (dir, '/');
+
+              g_assert (slash != NULL);
+              *slash = '\0';
+            }
+
+          g_clear_pointer (&gconv_dir_in_provider, g_free);
+          gconv_dir_in_provider = g_build_filename ("/usr", dir, "gconv", NULL);
+
+          if (_srt_file_test_in_sysroot (self->provider_in_current_namespace,
+                                         -1,
+                                         gconv_dir_in_provider,
+                                         G_FILE_TEST_IS_DIR))
+            {
+              g_hash_table_add (gconv_in_provider, g_steal_pointer (&gconv_dir_in_provider));
+              found = TRUE;
+            }
+        }
+
+      if (!found)
+        {
+          g_debug ("We were expecting to have the gconv modules directory in the "
+                   "provider to be located in \"%s/gconv\", but instead it is missing",
+                   dir);
+        }
+    }
+
+  return TRUE;
+}
+
 static gboolean
 pv_runtime_use_provider_graphics_stack (PvRuntime *self,
                                         FlatpakBwrap *bwrap,
@@ -3166,107 +3280,13 @@ pv_runtime_use_provider_graphics_stack (PvRuntime *self,
            * then we have to use its ld.so too. */
           if (g_file_test (libc, G_FILE_TEST_IS_SYMLINK))
             {
-              g_autoptr(FlatpakBwrap) temp_bwrap = NULL;
-              g_autofree char *libc_target = NULL;
-
-              if (!pv_runtime_take_ld_so_from_provider (self, arch,
-                                                        ld_so_in_runtime,
-                                                        bwrap, error))
-                return FALSE;
-
-              /* Collect miscellaneous libraries that libc might dlopen. */
-              temp_bwrap = pv_runtime_get_capsule_capture_libs (self, arch);
-              flatpak_bwrap_add_args (temp_bwrap,
-                                      "--dest", arch->libdir_in_current_namespace,
-                                      "if-exists:libidn2.so.0",
-                                      "if-exists:even-if-older:soname-match:libnss_compat.so.*",
-                                      "if-exists:even-if-older:soname-match:libnss_db.so.*",
-                                      "if-exists:even-if-older:soname-match:libnss_dns.so.*",
-                                      "if-exists:even-if-older:soname-match:libnss_files.so.*",
-                                      NULL);
-              flatpak_bwrap_finish (temp_bwrap);
-
-              if (!pv_bwrap_run_sync (temp_bwrap, NULL, error))
+              if (!pv_runtime_collect_libc_family (self, arch, bwrap,
+                                                   libc, ld_so_in_runtime,
+                                                   provider_in_container_namespace_guarded,
+                                                   gconv_in_provider,
+                                                   error))
                 return FALSE;
 
-              g_clear_pointer (&temp_bwrap, flatpak_bwrap_free);
-
-              libc_target = glnx_readlinkat_malloc (-1, libc, NULL, NULL);
-              if (libc_target != NULL)
-                {
-                  g_autofree gchar *dir = NULL;
-                  g_autofree gchar *gconv_dir_in_provider = NULL;
-                  gboolean found = FALSE;
-
-                  dir = g_path_get_dirname (libc_target);
-
-                  if (g_str_has_prefix (dir, provider_in_container_namespace_guarded))
-                    memmove (dir,
-                             dir + strlen (self->provider_in_container_namespace),
-                             strlen (dir) - strlen (self->provider_in_container_namespace) + 1);
-
-                  /* We are assuming that in the glibc "Makeconfig", $(libdir) was the same as
-                   * $(slibdir) (this is the upstream default) or the same as "/usr$(slibdir)"
-                   * (like in Debian without the mergerd /usr). We also assume that $(gconvdir)
-                   * had its default value "$(libdir)/gconv".
-                   * We check /usr first because otherwise, if the host is merged-/usr and the
-                   * container is not, we might end up binding /lib instead of /usr/lib
-                   * and that could cause issues. */
-                  if (g_str_has_prefix (dir, "/usr/"))
-                    memmove (dir, dir + strlen ("/usr"), strlen (dir) - strlen ("/usr") + 1);
-
-                  gconv_dir_in_provider = g_build_filename ("/usr", dir, "gconv", NULL);
-
-                  if (_srt_file_test_in_sysroot (self->provider_in_current_namespace,
-                                                 -1,
-                                                 gconv_dir_in_provider,
-                                                 G_FILE_TEST_IS_DIR))
-                    {
-                      g_hash_table_add (gconv_in_provider, g_steal_pointer (&gconv_dir_in_provider));
-                      found = TRUE;
-                    }
-
-                  if (!found)
-                    {
-                      /* Try again without hwcaps subdirectories.
-                       * For example, libc6-i386 on SteamOS 2 'brewmaster'
-                       * contains /lib/i386-linux-gnu/i686/cmov/libc.so.6,
-                       * for which we want gconv modules from
-                       * /usr/lib/i386-linux-gnu/gconv, not from
-                       * /usr/lib/i386-linux-gnu/i686/cmov/gconv. */
-                      while (g_str_has_suffix (dir, "/cmov") ||
-                             g_str_has_suffix (dir, "/i686") ||
-                             g_str_has_suffix (dir, "/sse2") ||
-                             g_str_has_suffix (dir, "/tls") ||
-                             g_str_has_suffix (dir, "/x86_64"))
-                        {
-                          char *slash = strrchr (dir, '/');
-
-                          g_assert (slash != NULL);
-                          *slash = '\0';
-                        }
-
-                      g_clear_pointer (&gconv_dir_in_provider, g_free);
-                      gconv_dir_in_provider = g_build_filename ("/usr", dir, "gconv", NULL);
-
-                      if (_srt_file_test_in_sysroot (self->provider_in_current_namespace,
-                                                     -1,
-                                                     gconv_dir_in_provider,
-                                                     G_FILE_TEST_IS_DIR))
-                        {
-                          g_hash_table_add (gconv_in_provider, g_steal_pointer (&gconv_dir_in_provider));
-                          found = TRUE;
-                        }
-                    }
-
-                  if (!found)
-                    {
-                      g_debug ("We were expecting to have the gconv modules directory in the "
-                               "provider to be located in \"%s/gconv\", but instead it is missing",
-                               dir);
-                    }
-                }
-
               self->any_libc_from_provider = TRUE;
             }
           else
-- 
GitLab