From 66f3ecceb1ee9fb62c62b8148995d8acc3c0124d Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Tue, 25 Feb 2020 16:57:59 +0000
Subject: [PATCH] runtime: Factor out pv_runtime_use_host_graphics_stack()

Signed-off-by: Simon McVittie <smcv@collabora.com>
---
 src/runtime.c | 214 ++++++++++++++++++++++++++++----------------------
 1 file changed, 122 insertions(+), 92 deletions(-)

diff --git a/src/runtime.c b/src/runtime.c
index c5a475bd6..c795d7d6e 100644
--- a/src/runtime.c
+++ b/src/runtime.c
@@ -55,6 +55,8 @@ struct _PvRuntime
   gchar *overrides_bin;
   gchar *container_access;
   FlatpakBwrap *container_access_adverb;
+  gboolean any_libc_from_host;
+  gboolean all_libc_from_host;
 };
 
 struct _PvRuntimeClass
@@ -99,9 +101,15 @@ static const char * const libquals[] =
   "lib32"
 };
 
+static gboolean pv_runtime_use_host_graphics_stack (PvRuntime *self,
+                                                    FlatpakBwrap *bwrap,
+                                                    GError **error);
+
 static void
 pv_runtime_init (PvRuntime *self)
 {
+  self->any_libc_from_host = FALSE;
+  self->all_libc_from_host = FALSE;
 }
 
 static void
@@ -832,39 +840,16 @@ bind_runtime (PvRuntime *self,
     NULL
   };
   g_autofree gchar *xrd = g_strdup_printf ("/run/user/%ld", (long) geteuid ());
-  gsize i, j;
+  gsize i;
   const gchar *member;
-  g_autoptr(GString) dri_path = g_string_new ("");
-  g_autoptr(GString) egl_path = g_string_new ("");
-  g_autoptr(GString) vulkan_path = g_string_new ("");
-  gboolean any_architecture_works = FALSE;
-  gboolean any_libc_from_host = FALSE;
-  gboolean all_libc_from_host = TRUE;
-  gboolean all_libdrm_from_host = TRUE;
-  g_autoptr(GHashTable) libdrm_data_from_host = g_hash_table_new_full (g_str_hash, g_str_equal,
-                                                                       g_free, NULL);
-  g_autofree gchar *libdrm_data_in_runtime = NULL;
-  g_autofree gchar *best_libdrm_data_from_host = NULL;
-  g_autofree gchar *localedef = NULL;
-  g_autofree gchar *dir_on_host = NULL;
-  g_autoptr(SrtSystemInfo) system_info = srt_system_info_new (NULL);
-  g_autoptr(SrtObjectList) egl_icds = NULL;
-  g_autoptr(SrtObjectList) vulkan_icds = NULL;
-  g_autoptr(GPtrArray) egl_icd_details = NULL;      /* (element-type IcdDetails) */
-  g_autoptr(GPtrArray) vulkan_icd_details = NULL;   /* (element-type IcdDetails) */
-  guint n_egl_icds;
-  guint n_vulkan_icds;
-  const GList *icd_iter;
 
   g_return_val_if_fail (PV_IS_RUNTIME (self), FALSE);
+  g_return_val_if_fail (!pv_bwrap_was_finished (bwrap), FALSE);
   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
   if (!pv_bwrap_bind_usr (bwrap, self->source_files, "/", error))
     return FALSE;
 
-  if (!pv_runtime_provide_container_access (self, error))
-    return FALSE;
-
   flatpak_bwrap_add_args (bwrap,
                           "--setenv", "XDG_RUNTIME_DIR", xrd,
                           "--tmpfs", "/run",
@@ -873,6 +858,9 @@ bind_runtime (PvRuntime *self,
                           "--symlink", "../run", "/var/run",
                           NULL);
 
+  if (!pv_bwrap_bind_usr (bwrap, "/", "/run/host", error))
+    return FALSE;
+
   for (i = 0; i < G_N_ELEMENTS (bind_mutable); i++)
     {
       g_autofree gchar *path = g_build_filename (self->source_files,
@@ -952,6 +940,107 @@ bind_runtime (PvRuntime *self,
                             "--ro-bind", "/etc/group", "/etc/group",
                             NULL);
 
+  if (!pv_runtime_use_host_graphics_stack (self, bwrap, error))
+    return FALSE;
+
+  /* This needs to be done after pv_runtime_use_host_graphics_stack()
+   * has decided whether to bring in the host system's libc. */
+  ensure_locales (self, self->any_libc_from_host, bwrap);
+
+  /* These can add data fds to @bwrap, so they must come last - after
+   * other functions stop using @bwrap as a basis for their own bwrap
+   * invocations with flatpak_bwrap_append_bwrap().
+   * Otherwise, when flatpak_bwrap_append_bwrap() calls
+   * flatpak_bwrap_steal_fds(), it will make the original FlatpakBwrap
+   * unusable. */
+
+  flatpak_run_add_wayland_args (bwrap);
+  flatpak_run_add_x11_args (bwrap, TRUE);
+  flatpak_run_add_pulseaudio_args (bwrap);
+  flatpak_run_add_session_dbus_args (bwrap);
+  flatpak_run_add_system_dbus_args (bwrap);
+  pv_bwrap_copy_tree (bwrap, self->overrides, "/overrides");
+
+  /* /etc/localtime and /etc/resolv.conf can not exist (or be symlinks to
+   * non-existing targets), in which case we don't want to attempt to create
+   * bogus symlinks or bind mounts, as that will cause flatpak run to fail.
+   */
+  if (g_file_test ("/etc/localtime", G_FILE_TEST_EXISTS))
+    {
+      g_autofree char *target = NULL;
+      gboolean is_reachable = FALSE;
+      g_autofree char *tz = flatpak_get_timezone ();
+      g_autofree char *timezone_content = g_strdup_printf ("%s\n", tz);
+
+      target = glnx_readlinkat_malloc (-1, "/etc/localtime", NULL, NULL);
+
+      if (target != NULL)
+        {
+          g_autoptr(GFile) base_file = NULL;
+          g_autoptr(GFile) target_file = NULL;
+          g_autofree char *target_canonical = NULL;
+
+          base_file = g_file_new_for_path ("/etc");
+          target_file = g_file_resolve_relative_path (base_file, target);
+          target_canonical = g_file_get_path (target_file);
+
+          is_reachable = g_str_has_prefix (target_canonical, "/usr/");
+        }
+
+      if (is_reachable)
+        {
+          flatpak_bwrap_add_args (bwrap,
+                                  "--symlink", target, "/etc/localtime",
+                                  NULL);
+        }
+      else
+        {
+          flatpak_bwrap_add_args (bwrap,
+                                  "--ro-bind", "/etc/localtime", "/etc/localtime",
+                                  NULL);
+        }
+
+      flatpak_bwrap_add_args_data (bwrap, "timezone",
+                                   timezone_content, -1, "/etc/timezone",
+                                   NULL);
+    }
+
+  return TRUE;
+}
+
+static gboolean
+pv_runtime_use_host_graphics_stack (PvRuntime *self,
+                                    FlatpakBwrap *bwrap,
+                                    GError **error)
+{
+  gsize i, j;
+  g_autoptr(GString) dri_path = g_string_new ("");
+  g_autoptr(GString) egl_path = g_string_new ("");
+  g_autoptr(GString) vulkan_path = g_string_new ("");
+  gboolean any_architecture_works = FALSE;
+  g_autofree gchar *localedef = NULL;
+  g_autofree gchar *dir_on_host = NULL;
+  g_autoptr(SrtSystemInfo) system_info = srt_system_info_new (NULL);
+  g_autoptr(SrtObjectList) egl_icds = NULL;
+  g_autoptr(SrtObjectList) vulkan_icds = NULL;
+  g_autoptr(GPtrArray) egl_icd_details = NULL;      /* (element-type IcdDetails) */
+  g_autoptr(GPtrArray) vulkan_icd_details = NULL;   /* (element-type IcdDetails) */
+  guint n_egl_icds;
+  guint n_vulkan_icds;
+  const GList *icd_iter;
+  gboolean all_libdrm_from_host = TRUE;
+  g_autoptr(GHashTable) libdrm_data_from_host = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                                       g_free, NULL);
+  g_autofree gchar *libdrm_data_in_runtime = NULL;
+  g_autofree gchar *best_libdrm_data_from_host = NULL;
+
+  g_return_val_if_fail (PV_IS_RUNTIME (self), FALSE);
+  g_return_val_if_fail (!pv_bwrap_was_finished (bwrap), FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  if (!pv_runtime_provide_container_access (self, error))
+    return FALSE;
+
   g_debug ("Enumerating EGL ICDs on host system...");
   egl_icds = srt_system_info_list_egl_icds (system_info, multiarch_tuples);
   n_egl_icds = g_list_length (egl_icds);
@@ -1013,6 +1102,10 @@ bind_runtime (PvRuntime *self,
 
   g_assert (multiarch_tuples[G_N_ELEMENTS (multiarch_tuples) - 1] == NULL);
 
+  /* We set this FALSE later if we decide not to use the host libc for
+   * some architecture. */
+  self->all_libc_from_host = TRUE;
+
   for (i = 0; i < G_N_ELEMENTS (multiarch_tuples) - 1; i++)
     {
       g_autofree gchar *tool = g_strdup_printf ("%s-capsule-capture-libs",
@@ -1276,11 +1369,11 @@ bind_runtime (PvRuntime *self,
 
               g_clear_pointer (&temp_bwrap, flatpak_bwrap_free);
 
-              any_libc_from_host = TRUE;
+              self->any_libc_from_host = TRUE;
             }
           else
             {
-              all_libc_from_host = FALSE;
+              self->all_libc_from_host = FALSE;
             }
 
           libdrm = g_build_filename (libdir_on_host, "libdrm.so.2", NULL);
@@ -1381,7 +1474,7 @@ bind_runtime (PvRuntime *self,
       return FALSE;
     }
 
-  if (any_libc_from_host && !all_libc_from_host)
+  if (self->any_libc_from_host && !self->all_libc_from_host)
     {
       /*
        * This shouldn't happen. It would mean that there exist at least
@@ -1399,7 +1492,7 @@ bind_runtime (PvRuntime *self,
                  "architectures! Arbitrarily using host locales.");
     }
 
-  if (any_libc_from_host)
+  if (self->any_libc_from_host)
     {
       g_debug ("Making host locale data visible in container");
 
@@ -1622,11 +1715,6 @@ bind_runtime (PvRuntime *self,
         }
     }
 
-  if (!pv_bwrap_bind_usr (bwrap, "/", "/run/host", error))
-    return FALSE;
-
-  ensure_locales (self, any_libc_from_host, bwrap);
-
   if (dri_path->len != 0)
       flatpak_bwrap_add_args (bwrap,
                               "--setenv", "LIBGL_DRIVERS_PATH", dri_path->str,
@@ -1658,64 +1746,6 @@ bind_runtime (PvRuntime *self,
                               "--unsetenv", "VK_ICD_FILENAMES",
                               NULL);
 
-  /* These can add data fds to @bwrap, so they must come last - after
-   * other functions stop using @bwrap as a basis for their own bwrap
-   * invocations with flatpak_bwrap_append_bwrap().
-   * Otherwise, when flatpak_bwrap_append_bwrap() calls
-   * flatpak_bwrap_steal_fds(), it will make the original FlatpakBwrap
-   * unusable. */
-
-  flatpak_run_add_wayland_args (bwrap);
-  flatpak_run_add_x11_args (bwrap, TRUE);
-  flatpak_run_add_pulseaudio_args (bwrap);
-  flatpak_run_add_session_dbus_args (bwrap);
-  flatpak_run_add_system_dbus_args (bwrap);
-  pv_bwrap_copy_tree (bwrap, self->overrides, "/overrides");
-
-  /* /etc/localtime and /etc/resolv.conf can not exist (or be symlinks to
-   * non-existing targets), in which case we don't want to attempt to create
-   * bogus symlinks or bind mounts, as that will cause flatpak run to fail.
-   */
-  if (g_file_test ("/etc/localtime", G_FILE_TEST_EXISTS))
-    {
-      g_autofree char *target = NULL;
-      gboolean is_reachable = FALSE;
-      g_autofree char *tz = flatpak_get_timezone ();
-      g_autofree char *timezone_content = g_strdup_printf ("%s\n", tz);
-
-      target = glnx_readlinkat_malloc (-1, "/etc/localtime", NULL, NULL);
-
-      if (target != NULL)
-        {
-          g_autoptr(GFile) base_file = NULL;
-          g_autoptr(GFile) target_file = NULL;
-          g_autofree char *target_canonical = NULL;
-
-          base_file = g_file_new_for_path ("/etc");
-          target_file = g_file_resolve_relative_path (base_file, target);
-          target_canonical = g_file_get_path (target_file);
-
-          is_reachable = g_str_has_prefix (target_canonical, "/usr/");
-        }
-
-      if (is_reachable)
-        {
-          flatpak_bwrap_add_args (bwrap,
-                                  "--symlink", target, "/etc/localtime",
-                                  NULL);
-        }
-      else
-        {
-          flatpak_bwrap_add_args (bwrap,
-                                  "--ro-bind", "/etc/localtime", "/etc/localtime",
-                                  NULL);
-        }
-
-      flatpak_bwrap_add_args_data (bwrap, "timezone",
-                                   timezone_content, -1, "/etc/timezone",
-                                   NULL);
-    }
-
   return TRUE;
 }
 
-- 
GitLab