From 3d79c339bc7a54683f80c6ab1624f6fa65f64820 Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Tue, 9 Jun 2020 20:22:43 +0100
Subject: [PATCH] wrap: Add an --only-prepare mode

This is primarily useful for testing and development: it lets us
generate the temporary sysroot and inspect its contents, even if we
are in a container (such as Docker or Flatpak) that does not give us
the necessary privileges to run bubblewrap and create a new user
namespace.

In particular, this will make it more straightforward for us to check
some of our assumptions when running on a non-Debian-derived host
system.

Signed-off-by: Simon McVittie <smcv@collabora.com>
---
 src/runtime.c | 27 +++++++++++++++++++++++++--
 src/wrap.c    | 32 ++++++++++++++++++++++++++++----
 2 files changed, 53 insertions(+), 6 deletions(-)

diff --git a/src/runtime.c b/src/runtime.c
index c940e3ea1..592e2a1d2 100644
--- a/src/runtime.c
+++ b/src/runtime.c
@@ -273,13 +273,36 @@ pv_runtime_set_property (GObject *object,
         path = g_value_get_string (value);
 
         if (path != NULL)
-          self->mutable_parent = flatpak_canonicalize_filename (path);
+          {
+            self->mutable_parent = realpath (path, NULL);
+
+            if (self->mutable_parent == NULL)
+              {
+                /* It doesn't exist. Keep the non-canonical path so we
+                 * can warn about it later */
+                self->mutable_parent = g_strdup (path);
+              }
+          }
+
         break;
 
       case PROP_SOURCE_FILES:
         /* Construct-only */
         g_return_if_fail (self->source_files == NULL);
-        self->source_files = g_value_dup_string (value);
+        path = g_value_get_string (value);
+
+        if (path != NULL)
+          {
+            self->source_files = realpath (path, NULL);
+
+            if (self->source_files == NULL)
+              {
+                /* It doesn't exist. Keep the non-canonical path so we
+                 * can warn about it later */
+                self->source_files = g_strdup (path);
+              }
+          }
+
         break;
 
       case PROP_TOOLS_DIRECTORY:
diff --git a/src/wrap.c b/src/wrap.c
index 8b6a7f0aa..386a14b02 100644
--- a/src/wrap.c
+++ b/src/wrap.c
@@ -100,7 +100,8 @@ find_bwrap (const char *tools_dir)
 }
 
 static gchar *
-check_bwrap (const char *tools_dir)
+check_bwrap (const char *tools_dir,
+             gboolean only_prepare)
 {
   g_autoptr(GError) local_error = NULL;
   GError **error = &local_error;
@@ -119,6 +120,14 @@ check_bwrap (const char *tools_dir)
     {
       g_warning ("Cannot find bwrap");
     }
+  else if (only_prepare)
+    {
+      /* With --only-prepare we don't necessarily expect to be able to run
+       * it anyway (we are probably in a Docker container that doesn't allow
+       * creation of nested user namespaces), so just assume that it's the
+       * right one. */
+      return g_steal_pointer (&bwrap_executable);
+    }
   else
     {
       int wait_status;
@@ -325,6 +334,7 @@ static gboolean opt_generate_locales = TRUE;
 static char *opt_home = NULL;
 static gboolean opt_host_fallback = FALSE;
 static gboolean opt_host_graphics = TRUE;
+static gboolean opt_only_prepare = FALSE;
 static gboolean opt_remove_game_overlay = FALSE;
 static PvShell opt_shell = PV_SHELL_NONE;
 static GPtrArray *opt_ld_preload = NULL;
@@ -632,6 +642,9 @@ static GOptionEntry options[] =
   { "test", '\0',
     G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, &opt_test,
     "Smoke test pressure-vessel-wrap and exit.", NULL },
+  { "only-prepare", '\0',
+    G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, &opt_only_prepare,
+    "Prepare runtime, but do not actually run anything.", NULL },
   { NULL }
 };
 
@@ -803,7 +816,7 @@ main (int argc,
       goto out;
     }
 
-  if (argc < 2 && !opt_test)
+  if (argc < 2 && !opt_test && !opt_only_prepare)
     {
       g_printerr ("%s: An executable to run is required\n",
                   g_get_prgname ());
@@ -888,6 +901,13 @@ main (int argc,
         }
     }
 
+  if (opt_only_prepare && opt_test)
+    {
+      g_printerr ("%s: --only-prepare and --test are mutually exclusive",
+                  g_get_prgname ());
+      goto out;
+    }
+
   /* Finished parsing arguments, so any subsequent failures will make
    * us exit 1. */
   ret = 1;
@@ -1006,7 +1026,7 @@ main (int argc,
   flatpak_bwrap_append_argsv (wrapped_command, &argv[1], argc - 1);
 
   g_debug ("Checking for bwrap...");
-  bwrap_executable = check_bwrap (tools_dir);
+  bwrap_executable = check_bwrap (tools_dir, opt_only_prepare);
 
   if (opt_test)
     {
@@ -1322,7 +1342,11 @@ main (int argc,
     pv_runtime_cleanup (runtime);
 
   flatpak_bwrap_finish (bwrap);
-  pv_bwrap_execve (bwrap, error);
+
+  if (opt_only_prepare)
+    ret = 0;
+  else
+    pv_bwrap_execve (bwrap, error);
 
 out:
   if (local_error != NULL)
-- 
GitLab