[gnome-builder/wip/gtk4-port: 1553/1774] libide/threading: port subprocess launcher to IdeUnixFDMap




commit d31f2f4a64a1df24e3be2c481860c0ad28857087
Author: Christian Hergert <chergert redhat com>
Date:   Thu Jun 16 16:16:40 2022 -0700

    libide/threading: port subprocess launcher to IdeUnixFDMap
    
    This ports the subprocess launching to using the new IdeUnixFDMap as a
    first test to see how the API is working for us. Ideally this will flush
    out any bugs quickly so we can use it for run contexts and other areas
    where you find something like a "FDMap" struct.

 .../threading/ide-flatpak-subprocess-private.h     |  27 +-
 src/libide/threading/ide-flatpak-subprocess.c      | 261 +++++++-------
 src/libide/threading/ide-subprocess-launcher.c     | 381 +++++++--------------
 3 files changed, 261 insertions(+), 408 deletions(-)
---
diff --git a/src/libide/threading/ide-flatpak-subprocess-private.h 
b/src/libide/threading/ide-flatpak-subprocess-private.h
index 64628c69b..3a9cf413a 100644
--- a/src/libide/threading/ide-flatpak-subprocess-private.h
+++ b/src/libide/threading/ide-flatpak-subprocess-private.h
@@ -21,6 +21,7 @@
 #pragma once
 
 #include "ide-subprocess.h"
+#include "ide-unix-fd-map.h"
 
 G_BEGIN_DECLS
 
@@ -28,23 +29,13 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (IdeFlatpakSubprocess, ide_flatpak_subprocess, IDE, FLATPAK_SUBPROCESS, GObject)
 
-typedef struct
-{
-  gint source_fd;
-  gint dest_fd;
-} IdeBreakoutFdMapping;
-
-IdeSubprocess *_ide_flatpak_subprocess_new (const gchar                 *cwd,
-                                             const gchar * const         *argv,
-                                             const gchar * const         *env,
-                                             GSubprocessFlags             flags,
-                                             gboolean                     clear_flags,
-                                             gint                         stdin_fd,
-                                             gint                         stdout_fd,
-                                             gint                         stderr_fd,
-                                             const IdeBreakoutFdMapping  *fd_map,
-                                             guint                        fd_map_len,
-                                             GCancellable                *cancellable,
-                                             GError                     **error) G_GNUC_INTERNAL;
+IdeSubprocess *_ide_flatpak_subprocess_new (const char          *cwd,
+                                            const char * const  *argv,
+                                            const char * const  *env,
+                                            GSubprocessFlags     flags,
+                                            gboolean             clear_flags,
+                                            IdeUnixFDMap        *unix_fd_map,
+                                            GCancellable        *cancellable,
+                                            GError             **error);
 
 G_END_DECLS
diff --git a/src/libide/threading/ide-flatpak-subprocess.c b/src/libide/threading/ide-flatpak-subprocess.c
index 065f597d4..3a5003c0c 100644
--- a/src/libide/threading/ide-flatpak-subprocess.c
+++ b/src/libide/threading/ide-flatpak-subprocess.c
@@ -58,29 +58,24 @@ struct _IdeFlatpakSubprocess
   gulong connection_closed_handler;
 
   GPid client_pid;
-  gint status;
+  int status;
 
   GSubprocessFlags flags;
 
   /* No reference */
   GThread *spawn_thread;
 
-  gchar **argv;
-  gchar **env;
-  gchar *cwd;
+  char **argv;
+  char **env;
+  char *cwd;
 
-  gchar *identifier;
-
-  gint stdin_fd;
-  gint stdout_fd;
-  gint stderr_fd;
+  char *identifier;
 
   GOutputStream *stdin_pipe;
   GInputStream *stdout_pipe;
   GInputStream *stderr_pipe;
 
-  IdeBreakoutFdMapping *fd_mapping;
-  guint fd_mapping_len;
+  IdeUnixFDMap *unix_fd_map;
 
   GMainContext *main_context;
 
@@ -139,29 +134,31 @@ struct _IdeFlatpakSubprocess
  */
 typedef struct
 {
-  const gchar *stdin_data;
-  gsize stdin_length;
-  gsize stdin_offset;
+  const char          *stdin_data;
+  gsize                stdin_length;
+  gsize                stdin_offset;
 
-  gboolean add_nul;
+  gboolean             add_nul;
 
-  GInputStream *stdin_buf;
+  GInputStream        *stdin_buf;
   GMemoryOutputStream *stdout_buf;
   GMemoryOutputStream *stderr_buf;
 
-  GCancellable *cancellable;
-  GSource      *cancellable_source;
+  GCancellable        *cancellable;
+  GSource             *cancellable_source;
 
-  guint         outstanding_ops;
-  gboolean      reported_error;
+  guint                outstanding_ops;
+  gboolean             reported_error;
 } CommunicateState;
 
 enum {
   PROP_0,
   PROP_ARGV,
+  PROP_CLEAR_ENV,
   PROP_CWD,
   PROP_ENV,
   PROP_FLAGS,
+  PROP_UNIX_FD_MAP,
   N_PROPS
 };
 
@@ -180,7 +177,7 @@ static CommunicateState *ide_flatpak_subprocess_communicate_internal (IdeFlatpak
 
 static GParamSpec *properties [N_PROPS];
 
-static const gchar *
+static const char *
 ide_flatpak_subprocess_get_identifier (IdeSubprocess *subprocess)
 {
   IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)subprocess;
@@ -485,7 +482,7 @@ ide_flatpak_subprocess_get_if_exited (IdeSubprocess *subprocess)
   return WIFEXITED (self->status);
 }
 
-static gint
+static int
 ide_flatpak_subprocess_get_exit_status (IdeSubprocess *subprocess)
 {
   IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)subprocess;
@@ -510,7 +507,7 @@ ide_flatpak_subprocess_get_if_signaled (IdeSubprocess *subprocess)
   return WIFSIGNALED (self->status);
 }
 
-static gint
+static int
 ide_flatpak_subprocess_get_term_sig (IdeSubprocess *subprocess)
 {
   IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)subprocess;
@@ -521,7 +518,7 @@ ide_flatpak_subprocess_get_term_sig (IdeSubprocess *subprocess)
   return WTERMSIG (self->status);
 }
 
-static gint
+static int
 ide_flatpak_subprocess_get_status (IdeSubprocess *subprocess)
 {
   IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)subprocess;
@@ -534,7 +531,7 @@ ide_flatpak_subprocess_get_status (IdeSubprocess *subprocess)
 
 static void
 ide_flatpak_subprocess_send_signal (IdeSubprocess *subprocess,
-                                     gint           signal_num)
+                                     int           signal_num)
 {
   IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)subprocess;
 
@@ -945,7 +942,7 @@ subprocess_iface_init (IdeSubprocessInterface *iface)
 
 static void
 maybe_create_input_stream (GInputStream **ret,
-                           gint          *fdptr,
+                           int          *fdptr,
                            gboolean       needs_stream)
 {
   g_assert (ret != NULL);
@@ -972,7 +969,7 @@ maybe_create_input_stream (GInputStream **ret,
 
 static void
 maybe_create_output_stream (GOutputStream **ret,
-                            gint           *fdptr,
+                            int           *fdptr,
                             gboolean        needs_stream)
 {
   g_assert (ret != NULL);
@@ -999,7 +996,7 @@ maybe_create_output_stream (GOutputStream **ret,
 
 static void
 ide_flatpak_subprocess_complete_command_locked (IdeFlatpakSubprocess *self,
-                                                 gint                   exit_status)
+                                                int                  exit_status)
 {
   GList *waiting;
 
@@ -1046,10 +1043,10 @@ ide_flatpak_subprocess_complete_command_locked (IdeFlatpakSubprocess *self,
 
 static void
 host_command_exited_cb (GDBusConnection *connection,
-                        const gchar     *sender_name,
-                        const gchar     *object_path,
-                        const gchar     *interface_name,
-                        const gchar     *signal_name,
+                        const char      *sender_name,
+                        const char      *object_path,
+                        const char      *interface_name,
+                        const char      *signal_name,
                         GVariant        *parameters,
                         gpointer         user_data)
 {
@@ -1094,7 +1091,7 @@ host_command_exited_cb (GDBusConnection *connection,
 
 static void
 ide_flatpak_subprocess_cancelled (IdeFlatpakSubprocess *self,
-                                   GCancellable          *cancellable)
+                                  GCancellable         *cancellable)
 {
   IDE_ENTRY;
 
@@ -1107,7 +1104,7 @@ ide_flatpak_subprocess_cancelled (IdeFlatpakSubprocess *self,
 }
 
 static inline void
-maybe_close (gint *fd)
+maybe_close (int *fd)
 {
   g_assert (fd != NULL);
   g_assert (*fd >= -1);
@@ -1120,9 +1117,9 @@ maybe_close (gint *fd)
 
 static void
 ide_flatpak_subprocess_connection_closed (IdeFlatpakSubprocess *self,
-                                           gboolean               remote_peer_vanished,
-                                           const GError          *error,
-                                           GDBusConnection       *connection)
+                                          gboolean              remote_peer_vanished,
+                                          const GError         *error,
+                                          GDBusConnection      *connection)
 {
   g_autoptr(GMutexLocker) locker = NULL;
 
@@ -1143,8 +1140,8 @@ ide_flatpak_subprocess_connection_closed (IdeFlatpakSubprocess *self,
 
 static gboolean
 ide_flatpak_subprocess_initable_init (GInitable     *initable,
-                                       GCancellable  *cancellable,
-                                       GError       **error)
+                                      GCancellable  *cancellable,
+                                      GError       **error)
 {
   IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)initable;
   g_autoptr(GVariantBuilder) fd_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{uh}"));
@@ -1153,18 +1150,20 @@ ide_flatpak_subprocess_initable_init (GInitable     *initable,
   g_autoptr(GVariant) reply = NULL;
   g_autoptr(GVariant) params = NULL;
   guint32 client_pid = 0;
-  gint stdout_pair[2] = { -1, -1 };
-  gint stderr_pair[2] = { -1, -1 };
-  gint stdin_pair[2] = { -1, -1 };
-  gint stdin_handle = -1;
-  gint stdout_handle = -1;
-  gint stderr_handle = -1;
+  int stdout_pair[2] = { -1, -1 };
+  int stderr_pair[2] = { -1, -1 };
+  int stdin_pair[2] = { -1, -1 };
+  int stdin_handle = -1;
+  int stdout_handle = -1;
+  int stderr_handle = -1;
   gboolean ret = FALSE;
   guint flags = FLATPAK_HOST_COMMAND_FLAGS_WATCH_BUS;
+  guint length;
 
   IDE_ENTRY;
 
   g_assert (IDE_IS_FLATPAK_SUBPROCESS (self));
+  g_assert (IDE_IS_UNIX_FD_MAP (self->unix_fd_map));
   g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
   if (!(self->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, cancellable, error)))
@@ -1173,18 +1172,14 @@ ide_flatpak_subprocess_initable_init (GInitable     *initable,
   if (self->clear_env)
     flags |= FLATPAK_HOST_COMMAND_FLAGS_CLEAR_ENV;
 
-
-  /*
-   * Handle STDIN for the process.
+  /* Handle STDIN for the process.
    *
    * Make sure we handle inherit STDIN, a new pipe (so that the application can
    * get the stdin stream), or simply redirect to /dev/null.
    */
-  if (self->stdin_fd != -1)
+  if (-1 != (stdin_pair[0] = ide_unix_fd_map_steal_stdin (self->unix_fd_map)))
     {
       self->flags &= ~G_SUBPROCESS_FLAGS_STDIN_PIPE;
-      stdin_pair[0] = self->stdin_fd;
-      self->stdin_fd = -1;
     }
   else if (self->flags & G_SUBPROCESS_FLAGS_STDIN_INHERIT)
     {
@@ -1213,18 +1208,15 @@ ide_flatpak_subprocess_initable_init (GInitable     *initable,
     maybe_close (&stdin_pair[0]);
 
 
-  /*
-   * Setup STDOUT for the process.
+  /* Setup STDOUT for the process.
    *
    * Make sure we redirect STDOUT to our stdout, unless a pipe was requested
    * for the application to read. However, if silence was requested, redirect
    * to /dev/null.
    */
-  if (self->stdout_fd != -1)
+  if (-1 != (stdout_pair[1] = ide_unix_fd_map_steal_stdout (self->unix_fd_map)))
     {
       self->flags &= ~G_SUBPROCESS_FLAGS_STDOUT_PIPE;
-      stdout_pair[1] = self->stdout_fd;
-      self->stdout_fd = -1;
     }
   else if (self->flags & G_SUBPROCESS_FLAGS_STDOUT_SILENCE)
     {
@@ -1253,18 +1245,15 @@ ide_flatpak_subprocess_initable_init (GInitable     *initable,
     maybe_close (&stdout_pair[1]);
 
 
-  /*
-   * Handle STDERR for the process.
+  /* Handle STDERR for the process.
    *
    * If silence is requested, we simply redirect to /dev/null. If the
    * application requested to read from the subprocesses stderr, then we need
    * to create a pipe. Otherwose, merge stderr into our own stderr.
    */
-  if (self->stderr_fd != -1)
+  if (-1 != (stderr_pair[1] = ide_unix_fd_map_steal_stderr (self->unix_fd_map)))
     {
       self->flags &= ~G_SUBPROCESS_FLAGS_STDERR_PIPE;
-      stderr_pair[1] = self->stderr_fd;
-      self->stderr_fd = -1;
     }
   else if (self->flags & G_SUBPROCESS_FLAGS_STDERR_SILENCE)
     {
@@ -1293,39 +1282,32 @@ ide_flatpak_subprocess_initable_init (GInitable     *initable,
     maybe_close (&stderr_pair[1]);
 
 
-  /*
-   * Build our FDs for the message.
-   */
+  /* Build our FDs for the message. */
   g_variant_builder_add (fd_builder, "{uh}", 0, stdin_handle);
   g_variant_builder_add (fd_builder, "{uh}", 1, stdout_handle);
   g_variant_builder_add (fd_builder, "{uh}", 2, stderr_handle);
 
 
-  /*
-   * Now add the rest of our FDs that we might need to map in for which
+  /* Now add the rest of our FDs that we might need to map in for which
    * the subprocess launcher tried to map.
    */
-  for (guint i = 0; i < self->fd_mapping_len; i++)
+  length = ide_unix_fd_map_get_length (self->unix_fd_map);
+  for (guint i = 0; i < length; i++)
     {
-      const IdeBreakoutFdMapping *map = &self->fd_mapping[i];
-      g_autoptr(GError) fd_error = NULL;
-      gint dest_handle;
+      int source_fd;
+      int dest_fd;
 
-      dest_handle = g_unix_fd_list_append (fd_list, map->source_fd, &fd_error);
-
-      if (dest_handle != -1)
-        g_variant_builder_add (fd_builder, "{uh}", map->dest_fd, dest_handle);
-      else
-        g_warning ("%s", fd_error->message);
+      if (-1 != (source_fd = ide_unix_fd_map_peek (self->unix_fd_map, i, &dest_fd)))
+        {
+          int dest_handle = g_unix_fd_list_append (fd_list, source_fd, NULL);
 
-      close (map->source_fd);
+          if (dest_handle != -1)
+            g_variant_builder_add (fd_builder, "{uh}", dest_fd, dest_handle);
+        }
     }
 
-  /*
-   * We don't want to allow these FDs to be used again.
-   */
-  self->fd_mapping_len = 0;
-  g_clear_pointer (&self->fd_mapping, g_free);
+  /* We don't want to allow these FDs to be used again. */
+  g_clear_object (&self->unix_fd_map);
 
 
   /*
@@ -1343,10 +1325,10 @@ ide_flatpak_subprocess_initable_init (GInitable     *initable,
     {
       for (guint i = 0; self->env[i]; i++)
         {
-          const gchar *pair = self->env[i];
-          const gchar *eq = strchr (pair, '=');
-          const gchar *val = eq ? eq + 1 : "";
-          g_autofree gchar *key = eq ? g_strndup (pair, eq - pair) : g_strdup (pair);
+          const char *pair = self->env[i];
+          const char *eq = strchr (pair, '=');
+          const char *val = eq ? eq + 1 : "";
+          g_autofree char *key = eq ? g_strndup (pair, eq - pair) : g_strdup (pair);
 
           g_variant_builder_add (env_builder, "{ss}", key, val);
         }
@@ -1410,7 +1392,7 @@ ide_flatpak_subprocess_initable_init (GInitable     *initable,
 
 #ifdef IDE_ENABLE_TRACE
   {
-    g_autofree gchar *str = g_variant_print (params, TRUE);
+    g_autofree char *str = g_variant_print (params, TRUE);
     IDE_TRACE_MSG ("Calling HostCommand with %s", str);
   }
 #endif
@@ -1474,9 +1456,9 @@ initiable_iface_init (GInitableIface *iface)
   iface->init = ide_flatpak_subprocess_initable_init;
 }
 
-G_DEFINE_TYPE_EXTENDED (IdeFlatpakSubprocess, ide_flatpak_subprocess, G_TYPE_OBJECT, G_TYPE_FLAG_FINAL,
-                        G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initiable_iface_init)
-                        G_IMPLEMENT_INTERFACE (IDE_TYPE_SUBPROCESS, subprocess_iface_init))
+G_DEFINE_FINAL_TYPE_WITH_CODE (IdeFlatpakSubprocess, ide_flatpak_subprocess, G_TYPE_OBJECT,
+                               G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initiable_iface_init)
+                               G_IMPLEMENT_INTERFACE (IDE_TYPE_SUBPROCESS, subprocess_iface_init))
 
 static void
 ide_flatpak_subprocess_dispose (GObject *object)
@@ -1522,23 +1504,11 @@ ide_flatpak_subprocess_finalize (GObject *object)
   g_clear_object (&self->stdout_pipe);
   g_clear_object (&self->stderr_pipe);
   g_clear_object (&self->connection);
+  g_clear_object (&self->unix_fd_map);
 
   g_mutex_clear (&self->waiter_mutex);
   g_cond_clear (&self->waiter_cond);
 
-  if (self->stdin_fd != -1)
-    close (self->stdin_fd);
-
-  if (self->stdout_fd != -1)
-    close (self->stdout_fd);
-
-  if (self->stderr_fd != -1)
-    close (self->stderr_fd);
-
-  for (guint i = 0; i < self->fd_mapping_len; i++)
-    close (self->fd_mapping[i].source_fd);
-  g_clear_pointer (&self->fd_mapping, g_free);
-
   G_OBJECT_CLASS (ide_flatpak_subprocess_parent_class)->finalize (object);
 
   IDE_EXIT;
@@ -1546,14 +1516,18 @@ ide_flatpak_subprocess_finalize (GObject *object)
 
 static void
 ide_flatpak_subprocess_get_property (GObject    *object,
-                                      guint       prop_id,
-                                      GValue     *value,
-                                      GParamSpec *pspec)
+                                     guint       prop_id,
+                                     GValue     *value,
+                                     GParamSpec *pspec)
 {
   IdeFlatpakSubprocess *self = IDE_FLATPAK_SUBPROCESS (object);
 
   switch (prop_id)
     {
+    case PROP_CLEAR_ENV:
+      g_value_set_boolean (value, self->clear_env);
+      break;
+
     case PROP_CWD:
       g_value_set_string (value, self->cwd);
       break;
@@ -1570,6 +1544,10 @@ ide_flatpak_subprocess_get_property (GObject    *object,
       g_value_set_flags (value, self->flags);
       break;
 
+    case PROP_UNIX_FD_MAP:
+      g_value_set_object (value, self->unix_fd_map);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -1577,22 +1555,26 @@ ide_flatpak_subprocess_get_property (GObject    *object,
 
 static void
 ide_flatpak_subprocess_set_property (GObject      *object,
-                                      guint         prop_id,
-                                      const GValue *value,
-                                      GParamSpec   *pspec)
+                                     guint         prop_id,
+                                     const GValue *value,
+                                     GParamSpec   *pspec)
 {
   IdeFlatpakSubprocess *self = IDE_FLATPAK_SUBPROCESS (object);
 
   switch (prop_id)
     {
-    case PROP_CWD:
-      self->cwd = g_value_dup_string (value);
-      break;
-
     case PROP_ARGV:
       self->argv = g_value_dup_boxed (value);
       break;
 
+    case PROP_CLEAR_ENV:
+      self->clear_env = g_value_get_boolean (value);
+      break;
+
+    case PROP_CWD:
+      self->cwd = g_value_dup_string (value);
+      break;
+
     case PROP_ENV:
       self->env = g_value_dup_boxed (value);
       break;
@@ -1601,6 +1583,12 @@ ide_flatpak_subprocess_set_property (GObject      *object,
       self->flags = g_value_get_flags (value);
       break;
 
+    case PROP_UNIX_FD_MAP:
+      self->unix_fd_map = g_value_dup_object (value);
+      if (self->unix_fd_map == NULL)
+        self->unix_fd_map = ide_unix_fd_map_new ();
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -1616,6 +1604,11 @@ ide_flatpak_subprocess_class_init (IdeFlatpakSubprocessClass *klass)
   object_class->get_property = ide_flatpak_subprocess_get_property;
   object_class->set_property = ide_flatpak_subprocess_set_property;
 
+  properties [PROP_CLEAR_ENV] =
+    g_param_spec_boolean ("clear-env", NULL, NULL,
+                          FALSE,
+                          (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
   properties [PROP_CWD] =
     g_param_spec_string ("cwd",
                          "Current Working Directory",
@@ -1645,6 +1638,11 @@ ide_flatpak_subprocess_class_init (IdeFlatpakSubprocessClass *klass)
                         G_SUBPROCESS_FLAGS_NONE,
                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
 
+  properties [PROP_UNIX_FD_MAP] =
+    g_param_spec_object ("unix-fd-map", NULL, NULL,
+                         IDE_TYPE_UNIX_FD_MAP,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
   g_object_class_install_properties (object_class, N_PROPS, properties);
 }
 
@@ -1653,10 +1651,6 @@ ide_flatpak_subprocess_init (IdeFlatpakSubprocess *self)
 {
   IDE_ENTRY;
 
-  self->stdin_fd = -1;
-  self->stdout_fd = -1;
-  self->stderr_fd = -1;
-
   g_mutex_init (&self->waiter_mutex);
   g_cond_init (&self->waiter_cond);
 
@@ -1664,40 +1658,31 @@ ide_flatpak_subprocess_init (IdeFlatpakSubprocess *self)
 }
 
 IdeSubprocess *
-_ide_flatpak_subprocess_new (const gchar                 *cwd,
-                              const gchar * const         *argv,
-                              const gchar * const         *env,
-                              GSubprocessFlags             flags,
-                              gboolean                     clear_env,
-                              gint                         stdin_fd,
-                              gint                         stdout_fd,
-                              gint                         stderr_fd,
-                              const IdeBreakoutFdMapping  *fd_mapping,
-                              guint                        fd_mapping_len,
-                              GCancellable                *cancellable,
-                              GError                     **error)
+_ide_flatpak_subprocess_new (const char          *cwd,
+                             const char * const  *argv,
+                             const char * const  *env,
+                             GSubprocessFlags     flags,
+                             gboolean             clear_env,
+                             IdeUnixFDMap        *unix_fd_map,
+                             GCancellable        *cancellable,
+                             GError             **error)
 {
   g_autoptr(IdeFlatpakSubprocess) ret = NULL;
 
   g_return_val_if_fail (argv != NULL, NULL);
   g_return_val_if_fail (argv[0] != NULL, NULL);
+  g_return_val_if_fail (!unix_fd_map || IDE_IS_UNIX_FD_MAP (unix_fd_map), NULL);
+  g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), NULL);
 
   ret = g_object_new (IDE_TYPE_FLATPAK_SUBPROCESS,
                       "cwd", cwd,
                       "argv", argv,
+                      "clear-env", clear_env,
                       "env", env,
                       "flags", flags,
+                      "unix-fd-map", unix_fd_map,
                       NULL);
 
-  ret->clear_env = clear_env;
-  ret->stdin_fd = stdin_fd;
-  ret->stdout_fd = stdout_fd;
-  ret->stderr_fd = stderr_fd;
-
-  ret->fd_mapping = g_new0 (IdeBreakoutFdMapping, fd_mapping_len);
-  ret->fd_mapping_len = fd_mapping_len;
-  memcpy (ret->fd_mapping, fd_mapping, sizeof(IdeBreakoutFdMapping) * fd_mapping_len);
-
   if (!g_initable_init (G_INITABLE (ret), cancellable, error))
     return NULL;
 
diff --git a/src/libide/threading/ide-subprocess-launcher.c b/src/libide/threading/ide-subprocess-launcher.c
index ffa3c9208..7e5daf93a 100644
--- a/src/libide/threading/ide-subprocess-launcher.c
+++ b/src/libide/threading/ide-subprocess-launcher.c
@@ -41,6 +41,7 @@
 #include "ide-flatpak-subprocess-private.h"
 #include "ide-simple-subprocess-private.h"
 #include "ide-subprocess-launcher.h"
+#include "ide-unix-fd-map.h"
 
 /* This comes from libide-io but we need access to it */
 #include "../io/ide-shell.h"
@@ -49,28 +50,17 @@
 
 typedef struct
 {
-  GSubprocessFlags  flags;
-
   GPtrArray        *argv;
-  gchar            *cwd;
-  gchar           **environ;
-  GArray           *fd_mapping;
-  gchar            *stdout_file_path;
-
-  gint              stdin_fd;
-  gint              stdout_fd;
-  gint              stderr_fd;
+  char             *cwd;
+  char            **environ;
+  char             *stdout_file_path;
+  IdeUnixFDMap     *unix_fd_map;
 
+  GSubprocessFlags  flags : 14;
   guint             run_on_host : 1;
   guint             clear_env : 1;
 } IdeSubprocessLauncherPrivate;
 
-typedef struct
-{
-  gint source_fd;
-  gint dest_fd;
-} FdMapping;
-
 G_DEFINE_TYPE_WITH_PRIVATE (IdeSubprocessLauncher, ide_subprocess_launcher, G_TYPE_OBJECT)
 
 enum {
@@ -122,7 +112,7 @@ ide_subprocess_launcher_kill_process_group (GCancellable *cancellable,
                                             GSubprocess  *subprocess)
 {
 #ifdef G_OS_UNIX
-  const gchar *ident;
+  const char *ident;
   pid_t pid;
 
   IDE_ENTRY;
@@ -204,10 +194,6 @@ ide_subprocess_launcher_spawn_host_worker (GTask        *task,
   IdeSubprocessLauncherPrivate *priv = ide_subprocess_launcher_get_instance_private (self);
   g_autoptr(IdeSubprocess) process = NULL;
   g_autoptr(GError) error = NULL;
-  g_autoptr(GArray) fds = NULL;
-  gint stdin_fd = -1;
-  gint stdout_fd = -1;
-  gint stderr_fd = -1;
 
   IDE_ENTRY;
 
@@ -215,56 +201,44 @@ ide_subprocess_launcher_spawn_host_worker (GTask        *task,
 
 #ifdef IDE_ENABLE_TRACE
   {
-    g_autofree gchar *str = NULL;
-    g_autofree gchar *env = NULL;
-    str = g_strjoinv (" ", (gchar **)priv->argv->pdata);
+    g_autofree char *str = NULL;
+    g_autofree char *env = NULL;
+    str = g_strjoinv (" ", (char **)priv->argv->pdata);
     env = priv->environ ? g_strjoinv (" ", priv->environ) : g_strdup ("");
     IDE_TRACE_MSG ("Launching '%s' with environment %s %s parent environment",
                    str, env, priv->clear_env ? "clearing" : "inheriting");
   }
 #endif
 
-  fds = g_steal_pointer (&priv->fd_mapping);
-
-  if (priv->stdin_fd != -1)
-    stdin_fd = dup (priv->stdin_fd);
-
-  if (priv->stdout_fd != -1)
-    stdout_fd = dup (priv->stdout_fd);
-  else if (priv->stdout_file_path != NULL)
-    stdout_fd = open (priv->stdout_file_path, O_WRONLY);
-
-  if (priv->stderr_fd != -1)
-    stderr_fd = dup (priv->stderr_fd);
-
-  process = _ide_flatpak_subprocess_new (priv->cwd,
-                                          (const gchar * const *)priv->argv->pdata,
-                                          (const gchar * const *)priv->environ,
-                                          priv->flags,
-                                          priv->clear_env,
-                                          stdin_fd,
-                                          stdout_fd,
-                                          stderr_fd,
-                                          fds ? (gpointer)fds->data : NULL,
-                                          fds ? fds->len : 0,
-                                          cancellable,
-                                          &error);
-
-  if (process == NULL)
+  if (priv->stdout_file_path != NULL &&
+      !ide_unix_fd_map_open_file (priv->unix_fd_map,
+                                  priv->stdout_file_path, O_WRONLY, STDOUT_FILENO,
+                                  &error))
     {
       g_task_return_error (task, g_steal_pointer (&error));
       IDE_EXIT;
     }
 
-  if (cancellable != NULL)
+  if (!(process = _ide_flatpak_subprocess_new (priv->cwd,
+                                               (const char * const *)priv->argv->pdata,
+                                               (const char * const *)priv->environ,
+                                               priv->flags,
+                                               priv->clear_env,
+                                               priv->unix_fd_map,
+                                               cancellable,
+                                               &error)))
     {
-      g_signal_connect_object (cancellable,
-                               "cancelled",
-                               G_CALLBACK (ide_subprocess_launcher_kill_host_process),
-                               process,
-                               0);
+      g_task_return_error (task, g_steal_pointer (&error));
+      IDE_EXIT;
     }
 
+  if (cancellable != NULL)
+    g_signal_connect_object (cancellable,
+                             "cancelled",
+                             G_CALLBACK (ide_subprocess_launcher_kill_host_process),
+                             process,
+                             0);
+
   g_task_return_pointer (task, g_steal_pointer (&process), g_object_unref);
 
   IDE_EXIT;
@@ -283,6 +257,7 @@ ide_subprocess_launcher_spawn_worker (GTask        *task,
   g_autoptr(IdeSubprocess) wrapped = NULL;
   g_autoptr(GError) error = NULL;
   gpointer child_data = NULL;
+  guint length;
 
   IDE_ENTRY;
 
@@ -292,10 +267,10 @@ ide_subprocess_launcher_spawn_worker (GTask        *task,
     child_data = GUINT_TO_POINTER (TRUE);
 
   {
-    g_autofree gchar *str = NULL;
-    g_autofree gchar *env = NULL;
+    g_autofree char *str = NULL;
+    g_autofree char *env = NULL;
 
-    str = g_strjoinv (" ", (gchar **)priv->argv->pdata);
+    str = g_strjoinv (" ", (char **)priv->argv->pdata);
     env = priv->environ ? g_strjoinv (" ", priv->environ) : g_strdup ("");
 
     g_debug ("Launching '%s' from directory '%s' with environment %s %s parent environment",
@@ -309,33 +284,22 @@ ide_subprocess_launcher_spawn_worker (GTask        *task,
   if (priv->stdout_file_path != NULL)
     g_subprocess_launcher_set_stdout_file_path (launcher, priv->stdout_file_path);
 
-  if (priv->stdin_fd != -1)
-    {
-      g_subprocess_launcher_take_stdin_fd (launcher, priv->stdin_fd);
-      priv->stdin_fd = -1;
-    }
-
-  if (priv->stdout_fd != -1)
+  length = ide_unix_fd_map_get_length (priv->unix_fd_map);
+  for (guint i = 0; i < length; i++)
     {
-      g_subprocess_launcher_take_stdout_fd (launcher, priv->stdout_fd);
-      priv->stdout_fd = -1;
-    }
+      int source_fd;
+      int dest_fd;
 
-  if (priv->stderr_fd != -1)
-    {
-      g_subprocess_launcher_take_stderr_fd (launcher, priv->stderr_fd);
-      priv->stderr_fd = -1;
-    }
-
-  if (priv->fd_mapping != NULL)
-    {
-      g_autoptr(GArray) ar = g_steal_pointer (&priv->fd_mapping);
-
-      for (guint i = 0; i < ar->len; i++)
+      if (-1 != (source_fd = ide_unix_fd_map_steal (priv->unix_fd_map, i, &dest_fd)))
         {
-          const FdMapping *map = &g_array_index (ar, FdMapping, i);
-
-          g_subprocess_launcher_take_fd (launcher, map->source_fd, map->dest_fd);
+          if (dest_fd == STDIN_FILENO)
+            g_subprocess_launcher_take_stdin_fd (launcher, source_fd);
+          else if (dest_fd == STDOUT_FILENO)
+            g_subprocess_launcher_take_stdout_fd (launcher, source_fd);
+          else if (dest_fd == STDERR_FILENO)
+            g_subprocess_launcher_take_stderr_fd (launcher, source_fd);
+          else
+            g_subprocess_launcher_take_fd (launcher, source_fd, dest_fd);
         }
     }
 
@@ -347,8 +311,8 @@ ide_subprocess_launcher_spawn_worker (GTask        *task,
    */
   if (priv->clear_env)
     {
-      gchar *envp[] = { NULL };
-      g_subprocess_launcher_set_environ (launcher, envp);
+      static const char *envp[] = { NULL };
+      g_subprocess_launcher_set_environ (launcher, (char **)envp);
     }
 
   /*
@@ -357,35 +321,30 @@ ide_subprocess_launcher_spawn_worker (GTask        *task,
    */
   if (priv->environ != NULL)
     {
-      for (guint i = 0; priv->environ[i] != NULL; i++)
+      for (guint i = 0; priv->environ[i]; i++)
         {
-          const gchar *pair = priv->environ[i];
-          const gchar *eq = strchr (pair, '=');
-          g_autofree gchar *key = g_strndup (pair, eq - pair);
-          const gchar *val = eq ? eq + 1 : NULL;
+          g_autofree char *key = NULL;
+          g_autofree char *value = NULL;
 
-          g_subprocess_launcher_setenv (launcher, key, val, TRUE);
+          if (ide_environ_parse (priv->environ[i], &key, &value))
+            g_subprocess_launcher_setenv (launcher, key, value, TRUE);
         }
     }
 
-  real = g_subprocess_launcher_spawnv (launcher,
-                                       (const gchar * const *)priv->argv->pdata,
-                                       &error);
-
-  if (real == NULL)
+  if (!(real = g_subprocess_launcher_spawnv (launcher,
+                                             (const char * const *)priv->argv->pdata,
+                                             &error)))
     {
       g_task_return_error (task, g_steal_pointer (&error));
       IDE_EXIT;
     }
 
   if (cancellable != NULL)
-    {
-      g_signal_connect_object (cancellable,
-                               "cancelled",
-                               G_CALLBACK (ide_subprocess_launcher_kill_process_group),
-                               real,
-                               0);
-    }
+    g_signal_connect_object (cancellable,
+                             "cancelled",
+                             G_CALLBACK (ide_subprocess_launcher_kill_process_group),
+                             real,
+                             0);
 
   wrapped = ide_simple_subprocess_new (real);
 
@@ -448,42 +407,12 @@ ide_subprocess_launcher_finalize (GObject *object)
   IdeSubprocessLauncher *self = (IdeSubprocessLauncher *)object;
   IdeSubprocessLauncherPrivate *priv = ide_subprocess_launcher_get_instance_private (self);
 
-  if (priv->fd_mapping != NULL)
-    {
-      for (guint i = 0; i < priv->fd_mapping->len; i++)
-        {
-          FdMapping *map = &g_array_index (priv->fd_mapping, FdMapping, i);
-
-          if (map->source_fd != -1)
-            close (map->source_fd);
-        }
-
-      g_clear_pointer (&priv->fd_mapping, g_array_unref);
-    }
-
+  g_clear_object (&priv->unix_fd_map);
   g_clear_pointer (&priv->argv, g_ptr_array_unref);
   g_clear_pointer (&priv->cwd, g_free);
   g_clear_pointer (&priv->environ, g_strfreev);
   g_clear_pointer (&priv->stdout_file_path, g_free);
 
-  if (priv->stdin_fd != -1)
-    {
-      close (priv->stdin_fd);
-      priv->stdin_fd = -1;
-    }
-
-  if (priv->stdout_fd != -1)
-    {
-      close (priv->stdout_fd);
-      priv->stdout_fd = -1;
-    }
-
-  if (priv->stderr_fd != -1)
-    {
-      close (priv->stderr_fd);
-      priv->stderr_fd = -1;
-    }
-
   G_OBJECT_CLASS (ide_subprocess_launcher_parent_class)->finalize (object);
 }
 
@@ -573,14 +502,14 @@ ide_subprocess_launcher_class_init (IdeSubprocessLauncherClass *klass)
                           "Clear Environment",
                           "If the environment should be cleared before setting environment variables.",
                           FALSE,
-                          (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
 
   properties [PROP_CWD] =
     g_param_spec_string ("cwd",
                          "Current Working Directory",
                          "Current Working Directory",
                          NULL,
-                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+                         (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
 
   properties [PROP_FLAGS] =
     g_param_spec_flags ("flags",
@@ -592,17 +521,17 @@ ide_subprocess_launcher_class_init (IdeSubprocessLauncherClass *klass)
 
   properties [PROP_ENVIRON] =
     g_param_spec_boxed ("environ",
-                        "Environ",
-                        "Environ",
+                        "Environment",
+                        "The environment variables for the subprocess",
                         G_TYPE_STRV,
-                        (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+                        (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
 
   properties [PROP_RUN_ON_HOST] =
     g_param_spec_boolean ("run-on-host",
                           "Run on Host",
                           "Run on Host",
                           FALSE,
-                          (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
 
   g_object_class_install_properties (object_class, N_PROPS, properties);
 }
@@ -614,9 +543,7 @@ ide_subprocess_launcher_init (IdeSubprocessLauncher *self)
 
   priv->clear_env = TRUE;
 
-  priv->stdin_fd = -1;
-  priv->stdout_fd = -1;
-  priv->stderr_fd = -1;
+  priv->unix_fd_map = ide_unix_fd_map_new ();
 
   priv->argv = g_ptr_array_new_with_free_func (g_free);
   g_ptr_array_add (priv->argv, NULL);
@@ -649,14 +576,14 @@ ide_subprocess_launcher_get_flags (IdeSubprocessLauncher *self)
   return priv->flags;
 }
 
-const gchar * const *
+const char * const *
 ide_subprocess_launcher_get_environ (IdeSubprocessLauncher *self)
 {
   IdeSubprocessLauncherPrivate *priv = ide_subprocess_launcher_get_instance_private (self);
 
   g_return_val_if_fail (IDE_IS_SUBPROCESS_LAUNCHER (self), NULL);
 
-  return (const gchar * const *)priv->environ;
+  return (const char * const *)priv->environ;
 }
 
 /**
@@ -669,22 +596,27 @@ ide_subprocess_launcher_get_environ (IdeSubprocessLauncher *self)
  */
 void
 ide_subprocess_launcher_set_environ (IdeSubprocessLauncher *self,
-                                     const gchar * const   *environ_)
+                                     const char * const    *environ_)
 {
   IdeSubprocessLauncherPrivate *priv = ide_subprocess_launcher_get_instance_private (self);
 
   g_return_if_fail (IDE_IS_SUBPROCESS_LAUNCHER (self));
 
-  if (priv->environ != (gchar **)environ_)
+  if (priv->environ == (char **)environ_)
+    return;
+
+  if ((priv->environ == NULL || environ_ == NULL) ||
+      !g_strv_equal ((const char * const *)priv->environ, environ_))
     {
       g_strfreev (priv->environ);
-      priv->environ = g_strdupv ((gchar **)environ_);
+      priv->environ = g_strdupv ((char **)environ_);
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ENVIRON]);
     }
 }
 
-const gchar *
+const char *
 ide_subprocess_launcher_getenv (IdeSubprocessLauncher *self,
-                                const gchar           *key)
+                                const char           *key)
 {
   IdeSubprocessLauncherPrivate *priv = ide_subprocess_launcher_get_instance_private (self);
 
@@ -696,8 +628,8 @@ ide_subprocess_launcher_getenv (IdeSubprocessLauncher *self,
 
 void
 ide_subprocess_launcher_setenv (IdeSubprocessLauncher *self,
-                                const gchar           *key,
-                                const gchar           *value,
+                                const char           *key,
+                                const char           *value,
                                 gboolean               replace)
 {
   IdeSubprocessLauncherPrivate *priv = ide_subprocess_launcher_get_instance_private (self);
@@ -713,7 +645,7 @@ ide_subprocess_launcher_setenv (IdeSubprocessLauncher *self,
 
 void
 ide_subprocess_launcher_push_argv (IdeSubprocessLauncher *self,
-                                   const gchar           *argv)
+                                   const char           *argv)
 {
   IdeSubprocessLauncherPrivate *priv = ide_subprocess_launcher_get_instance_private (self);
 
@@ -744,7 +676,7 @@ ide_subprocess_launcher_spawn (IdeSubprocessLauncher  *self,
 
 void
 ide_subprocess_launcher_set_cwd (IdeSubprocessLauncher *self,
-                                 const gchar           *cwd)
+                                 const char           *cwd)
 {
   IdeSubprocessLauncherPrivate *priv = ide_subprocess_launcher_get_instance_private (self);
 
@@ -761,7 +693,7 @@ ide_subprocess_launcher_set_cwd (IdeSubprocessLauncher *self,
     }
 }
 
-const gchar *
+const char *
 ide_subprocess_launcher_get_cwd (IdeSubprocessLauncher *self)
 {
   IdeSubprocessLauncherPrivate *priv = ide_subprocess_launcher_get_instance_private (self);
@@ -785,8 +717,8 @@ ide_subprocess_launcher_overlay_environment (IdeSubprocessLauncher *self,
       for (guint i = 0; i < n_items; i++)
         {
           g_autoptr(IdeEnvironmentVariable) var = NULL;
-          const gchar *key;
-          const gchar *value;
+          const char *key;
+          const char *value;
 
           var = g_list_model_get_item (G_LIST_MODEL (environment), i);
           key = ide_environment_variable_get_key (var);
@@ -810,7 +742,7 @@ ide_subprocess_launcher_overlay_environment (IdeSubprocessLauncher *self,
  */
 void
 ide_subprocess_launcher_push_args (IdeSubprocessLauncher *self,
-                                   const gchar * const   *args)
+                                   const char * const   *args)
 {
   g_return_if_fail (IDE_IS_SUBPROCESS_LAUNCHER (self));
 
@@ -821,11 +753,11 @@ ide_subprocess_launcher_push_args (IdeSubprocessLauncher *self,
     }
 }
 
-gchar *
+char *
 ide_subprocess_launcher_pop_argv (IdeSubprocessLauncher *self)
 {
   IdeSubprocessLauncherPrivate *priv = ide_subprocess_launcher_get_instance_private (self);
-  gchar *ret = NULL;
+  char *ret = NULL;
 
   g_return_val_if_fail (IDE_IS_SUBPROCESS_LAUNCHER (self), NULL);
 
@@ -913,50 +845,36 @@ ide_subprocess_launcher_set_clear_env (IdeSubprocessLauncher *self,
 
 void
 ide_subprocess_launcher_take_stdin_fd (IdeSubprocessLauncher *self,
-                                       gint                   stdin_fd)
+                                       int                    stdin_fd)
 {
   IdeSubprocessLauncherPrivate *priv = ide_subprocess_launcher_get_instance_private (self);
+  g_autoptr(GError) error = NULL;
 
   g_return_if_fail (IDE_IS_SUBPROCESS_LAUNCHER (self));
 
-  if (priv->stdin_fd != stdin_fd)
-    {
-      if (priv->stdin_fd != -1)
-        close (priv->stdin_fd);
-      priv->stdin_fd = stdin_fd;
-    }
+  ide_unix_fd_map_take (priv->unix_fd_map, stdin_fd, STDIN_FILENO);
 }
 
 void
 ide_subprocess_launcher_take_stdout_fd (IdeSubprocessLauncher *self,
-                                        gint                   stdout_fd)
+                                        int                    stdout_fd)
 {
   IdeSubprocessLauncherPrivate *priv = ide_subprocess_launcher_get_instance_private (self);
 
   g_return_if_fail (IDE_IS_SUBPROCESS_LAUNCHER (self));
 
-  if (priv->stdout_fd != stdout_fd)
-    {
-      if (priv->stdout_fd != -1)
-        close (priv->stdout_fd);
-      priv->stdout_fd = stdout_fd;
-    }
+  ide_unix_fd_map_take (priv->unix_fd_map, stdout_fd, STDOUT_FILENO);
 }
 
 void
 ide_subprocess_launcher_take_stderr_fd (IdeSubprocessLauncher *self,
-                                        gint                   stderr_fd)
+                                        int                    stderr_fd)
 {
   IdeSubprocessLauncherPrivate *priv = ide_subprocess_launcher_get_instance_private (self);
 
   g_return_if_fail (IDE_IS_SUBPROCESS_LAUNCHER (self));
 
-  if (priv->stderr_fd != stderr_fd)
-    {
-      if (priv->stderr_fd != -1)
-        close (priv->stderr_fd);
-      priv->stderr_fd = stderr_fd;
-    }
+  ide_unix_fd_map_take (priv->unix_fd_map, stderr_fd, STDERR_FILENO);
 }
 
 /**
@@ -970,7 +888,7 @@ ide_subprocess_launcher_take_stderr_fd (IdeSubprocessLauncher *self,
  */
 void
 ide_subprocess_launcher_set_argv (IdeSubprocessLauncher  *self,
-                                  const gchar * const    *args)
+                                  const char * const    *args)
 {
   IdeSubprocessLauncherPrivate *priv = ide_subprocess_launcher_get_instance_private (self);
 
@@ -987,20 +905,20 @@ ide_subprocess_launcher_set_argv (IdeSubprocessLauncher  *self,
   g_ptr_array_add (priv->argv, NULL);
 }
 
-const gchar * const *
+const char * const *
 ide_subprocess_launcher_get_argv (IdeSubprocessLauncher *self)
 {
   IdeSubprocessLauncherPrivate *priv = ide_subprocess_launcher_get_instance_private (self);
 
   g_return_val_if_fail (IDE_IS_SUBPROCESS_LAUNCHER (self), NULL);
 
-  return (const gchar * const *)priv->argv->pdata;
+  return (const char * const *)priv->argv->pdata;
 }
 
 void
 ide_subprocess_launcher_insert_argv (IdeSubprocessLauncher *self,
                                      guint                  index,
-                                     const gchar           *arg)
+                                     const char           *arg)
 {
   IdeSubprocessLauncherPrivate *priv = ide_subprocess_launcher_get_instance_private (self);
 
@@ -1015,10 +933,10 @@ ide_subprocess_launcher_insert_argv (IdeSubprocessLauncher *self,
 void
 ide_subprocess_launcher_replace_argv (IdeSubprocessLauncher *self,
                                       guint                  index,
-                                      const gchar           *arg)
+                                      const char           *arg)
 {
   IdeSubprocessLauncherPrivate *priv = ide_subprocess_launcher_get_instance_private (self);
-  gchar *old_arg;
+  char *old_arg;
 
   g_return_if_fail (IDE_IS_SUBPROCESS_LAUNCHER (self));
   g_return_if_fail (priv->argv->len > 0);
@@ -1033,28 +951,21 @@ ide_subprocess_launcher_replace_argv (IdeSubprocessLauncher *self,
 
 void
 ide_subprocess_launcher_take_fd (IdeSubprocessLauncher *self,
-                                 gint                   source_fd,
-                                 gint                   dest_fd)
+                                 int                    source_fd,
+                                 int                    dest_fd)
 {
   IdeSubprocessLauncherPrivate *priv = ide_subprocess_launcher_get_instance_private (self);
-  FdMapping map = {
-    .source_fd = source_fd,
-    .dest_fd = dest_fd
-  };
 
   g_return_if_fail (IDE_IS_SUBPROCESS_LAUNCHER (self));
   g_return_if_fail (source_fd > -1);
   g_return_if_fail (dest_fd > -1);
 
-  if (priv->fd_mapping == NULL)
-    priv->fd_mapping = g_array_new (FALSE, FALSE, sizeof (FdMapping));
-
-  g_array_append_val (priv->fd_mapping, map);
+  ide_unix_fd_map_take (priv->unix_fd_map, source_fd, dest_fd);
 }
 
 void
 ide_subprocess_launcher_set_stdout_file_path (IdeSubprocessLauncher *self,
-                                              const gchar           *stdout_file_path)
+                                              const char           *stdout_file_path)
 {
   IdeSubprocessLauncherPrivate *priv = ide_subprocess_launcher_get_instance_private (self);
 
@@ -1069,9 +980,9 @@ ide_subprocess_launcher_set_stdout_file_path (IdeSubprocessLauncher *self,
 
 void
 ide_subprocess_launcher_prepend_path (IdeSubprocessLauncher *self,
-                                      const gchar           *path)
+                                      const char           *path)
 {
-  const gchar *old_path;
+  const char *old_path;
 
   g_return_if_fail (IDE_IS_SUBPROCESS_LAUNCHER (self));
 
@@ -1082,7 +993,7 @@ ide_subprocess_launcher_prepend_path (IdeSubprocessLauncher *self,
 
   if (old_path != NULL)
     {
-      g_autofree gchar *new_path = g_strdup_printf ("%s:%s", path, old_path);
+      g_autofree char *new_path = g_strdup_printf ("%s:%s", path, old_path);
       ide_subprocess_launcher_setenv (self, "PATH", new_path, TRUE);
     }
   else
@@ -1093,9 +1004,9 @@ ide_subprocess_launcher_prepend_path (IdeSubprocessLauncher *self,
 
 void
 ide_subprocess_launcher_append_path (IdeSubprocessLauncher *self,
-                                     const gchar           *path)
+                                     const char           *path)
 {
-  const gchar *old_path;
+  const char *old_path;
 
   g_return_if_fail (IDE_IS_SUBPROCESS_LAUNCHER (self));
 
@@ -1106,7 +1017,7 @@ ide_subprocess_launcher_append_path (IdeSubprocessLauncher *self,
 
   if (old_path != NULL)
     {
-      g_autofree gchar *new_path = g_strdup_printf ("%s:%s", old_path, path);
+      g_autofree char *new_path = g_strdup_printf ("%s:%s", old_path, path);
       ide_subprocess_launcher_setenv (self, "PATH", new_path, TRUE);
     }
   else
@@ -1121,34 +1032,11 @@ ide_subprocess_launcher_get_needs_tty (IdeSubprocessLauncher *self)
   IdeSubprocessLauncherPrivate *priv = ide_subprocess_launcher_get_instance_private (self);
 
   g_return_val_if_fail (IDE_IS_SUBPROCESS_LAUNCHER (self), FALSE);
+  g_return_val_if_fail (IDE_IS_UNIX_FD_MAP (priv->unix_fd_map), FALSE);
 
-  if ((priv->stdin_fd != -1 && isatty (priv->stdin_fd)) ||
-      (priv->stdout_fd != -1 && isatty (priv->stdout_fd)) ||
-      (priv->stderr_fd != -1 && isatty (priv->stderr_fd)))
-    return TRUE;
-
-  if (priv->fd_mapping != NULL)
-    {
-      for (guint i = 0; i < priv->fd_mapping->len; i++)
-        {
-          const FdMapping *fdmap = &g_array_index (priv->fd_mapping, FdMapping, i);
-
-          switch (fdmap->dest_fd)
-            {
-            case STDIN_FILENO:
-            case STDOUT_FILENO:
-            case STDERR_FILENO:
-              if (isatty (fdmap->source_fd))
-                return TRUE;
-              break;
-
-            default:
-              break;
-            }
-        }
-    }
-
-  return FALSE;
+  return ide_unix_fd_map_stdin_isatty (priv->unix_fd_map) ||
+         ide_unix_fd_map_stdout_isatty (priv->unix_fd_map) ||
+         ide_unix_fd_map_stderr_isatty (priv->unix_fd_map);
 }
 
 /**
@@ -1162,29 +1050,18 @@ ide_subprocess_launcher_get_needs_tty (IdeSubprocessLauncher *self)
  *
  * Returns: an integer for the max-fd
  */
-gint
+int
 ide_subprocess_launcher_get_max_fd (IdeSubprocessLauncher *self)
 {
   IdeSubprocessLauncherPrivate *priv = ide_subprocess_launcher_get_instance_private (self);
-  gint max_fd = 2;
-
-  g_return_val_if_fail (IDE_IS_SUBPROCESS_LAUNCHER (self), 2);
 
-  if (priv->fd_mapping != NULL)
-    {
-      for (guint i = 0; i < priv->fd_mapping->len; i++)
-        {
-          const FdMapping *map = &g_array_index (priv->fd_mapping, FdMapping, i);
-
-          if (map->dest_fd > max_fd)
-            max_fd = map->dest_fd;
-        }
-    }
+  g_return_val_if_fail (IDE_IS_SUBPROCESS_LAUNCHER (self), -1);
+  g_return_val_if_fail (IDE_IS_UNIX_FD_MAP (priv->unix_fd_map), -1);
 
-  return max_fd;
+  return ide_unix_fd_map_get_max_dest_fd (priv->unix_fd_map);
 }
 
-const gchar *
+const char *
 ide_subprocess_launcher_get_arg (IdeSubprocessLauncher *self,
                                  guint                  pos)
 {
@@ -1203,7 +1080,7 @@ ide_subprocess_launcher_join_args_for_sh_c (IdeSubprocessLauncher *self,
                                             guint                  start_pos)
 {
   IdeSubprocessLauncherPrivate *priv = ide_subprocess_launcher_get_instance_private (self);
-  const gchar * const *argv;
+  const char * const *argv;
   GString *str;
 
   g_return_if_fail (IDE_IS_SUBPROCESS_LAUNCHER (self));
@@ -1214,7 +1091,7 @@ ide_subprocess_launcher_join_args_for_sh_c (IdeSubprocessLauncher *self,
 
   for (guint i = start_pos; argv[i] != NULL; i++)
     {
-      g_autofree gchar *quoted_string = g_shell_quote (argv[i]);
+      g_autofree char *quoted_string = g_shell_quote (argv[i]);
 
       if (i > 0)
         g_string_append_c (str, ' ');
@@ -1238,8 +1115,8 @@ ide_subprocess_launcher_join_args_for_sh_c (IdeSubprocessLauncher *self,
  * ide_subprocess_launcher_push_argv() and then freed.
  */
 void
-ide_subprocess_launcher_push_argv_format (IdeSubprocessLauncher  *self,
-                                          const char             *format,
+ide_subprocess_launcher_push_argv_format (IdeSubprocessLauncher *self,
+                                          const char            *format,
                                           ...)
 {
   g_autofree char *arg = NULL;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]