[gnome-builder] subprocess: allow generic FD mapping into IdeSubprocess and IdeRunner
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] subprocess: allow generic FD mapping into IdeSubprocess and IdeRunner
- Date: Tue, 21 Feb 2017 07:46:29 +0000 (UTC)
commit fce41c63999aced80679a089edb8f6ab63083b08
Author: Christian Hergert <chergert redhat com>
Date: Mon Feb 20 23:43:11 2017 -0800
subprocess: allow generic FD mapping into IdeSubprocess and IdeRunner
This provides the abstraction we need to be able to map an FD into a given
FD within the target process. Previously we could only do this for
stdin/stdout/stderr.
Additionally, this includes the same plumbing for IdeRunner which is our
more specific, higher-level abstraction for running programs/tests using
subprocess launchers.
libide/runner/ide-runner.c | 127 +++++++++++++++++++-
libide/runner/ide-runner.h | 3 +
.../subprocess/ide-breakout-subprocess-private.h | 28 +++--
libide/subprocess/ide-breakout-subprocess.c | 61 ++++++++--
libide/subprocess/ide-subprocess-launcher.c | 58 +++++++++
libide/subprocess/ide-subprocess-launcher.h | 3 +
6 files changed, 259 insertions(+), 21 deletions(-)
---
diff --git a/libide/runner/ide-runner.c b/libide/runner/ide-runner.c
index 67a7f3a..86c4c55 100644
--- a/libide/runner/ide-runner.c
+++ b/libide/runner/ide-runner.c
@@ -56,6 +56,12 @@ typedef struct
GSList *posthook_queue;
} IdeRunnerRunState;
+typedef struct
+{
+ gint source_fd;
+ gint dest_fd;
+} FdMapping;
+
enum {
PROP_0,
PROP_ARGV,
@@ -204,13 +210,28 @@ ide_runner_real_run_async (IdeRunner *self,
*/
if (priv->tty_fd != -1)
{
- IDE_TRACE_MSG ("Setting TTY fd to %d\n", priv->tty_fd);
+ IDE_TRACE_MSG ("Setting TTY fd to %d", priv->tty_fd);
ide_subprocess_launcher_take_stdin_fd (launcher, dup (priv->tty_fd));
ide_subprocess_launcher_take_stdout_fd (launcher, dup (priv->tty_fd));
ide_subprocess_launcher_take_stderr_fd (launcher, dup (priv->tty_fd));
}
/*
+ * Now map in any additionally requested FDs.
+ */
+ if (priv->fd_mapping != NULL)
+ {
+ g_autoptr(GArray) ar = g_steal_pointer (&priv->fd_mapping);
+
+ for (guint i = 0; i < ar->len; i++)
+ {
+ FdMapping *map = &g_array_index (ar, FdMapping, i);
+
+ ide_subprocess_launcher_take_fd (launcher, map->source_fd, map->dest_fd);
+ }
+ }
+
+ /*
* We want the runners to run on the host so that we aren't captive to
* our containing system (flatpak, jhbuild, etc).
*/
@@ -372,6 +393,22 @@ ide_runner_finalize (GObject *object)
g_queue_clear (&priv->argv);
g_clear_object (&priv->env);
+ 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);
+ map->source_fd = -1;
+ }
+ }
+ }
+
+ g_clear_pointer (&priv->fd_mapping, g_array_unref);
+
if (priv->tty_fd != -1)
{
close (priv->tty_fd);
@@ -954,3 +991,91 @@ ide_runner_set_tty (IdeRunner *self,
IDE_EXIT;
}
+
+static gint
+sort_fd_mapping (gconstpointer a,
+ gconstpointer b)
+{
+ const FdMapping *map_a = a;
+ const FdMapping *map_b = b;
+
+ return map_a->dest_fd - map_b->dest_fd;
+}
+
+/**
+ * ide_runner_take_fd:
+ * @self: An #IdeRunner
+ * @source_fd: the fd to map, this will be closed by #IdeRunner
+ * @dest_fd: the target FD in the spawned process, or -1 for next available
+ *
+ * This will ensure that @source_fd is mapped into the new process as @dest_fd.
+ * If @dest_fd is -1, then the next fd will be used and that value will be
+ * returned. Note that this is not a valid fd in the calling process, only
+ * within the destination process.
+ *
+ * Returns: @dest_fd or the FD or the next available dest_fd.
+ */
+gint
+ide_runner_take_fd (IdeRunner *self,
+ gint source_fd,
+ gint dest_fd)
+{
+ IdeRunnerPrivate *priv = ide_runner_get_instance_private (self);
+ FdMapping map = { -1, -1 };
+
+ g_return_val_if_fail (IDE_IS_RUNNER (self), -1);
+ g_return_val_if_fail (source_fd > -1, -1);
+
+ if (priv->fd_mapping == NULL)
+ priv->fd_mapping = g_array_new (FALSE, FALSE, sizeof (FdMapping));
+
+ /*
+ * Quick and dirty hack to take the next FD, won't deal with people mapping
+ * to 1024 well, but we can fix that when we come across it.
+ */
+ if (dest_fd < 0)
+ {
+ if (priv->fd_mapping->len == 0)
+ dest_fd = 3;
+ else
+ dest_fd = g_array_index (priv->fd_mapping, FdMapping, priv->fd_mapping->len - 1).dest_fd + 1;
+ }
+
+ map.source_fd = source_fd;
+ map.dest_fd = dest_fd;
+
+ g_array_append_val (priv->fd_mapping, map);
+ g_array_sort (priv->fd_mapping, sort_fd_mapping);
+
+ return dest_fd;
+}
+
+guint
+ide_runner_get_n_fd_mappings (IdeRunner *self)
+{
+ IdeRunnerPrivate *priv = ide_runner_get_instance_private (self);
+
+ g_return_val_if_fail (IDE_IS_RUNNER (self), 0);
+
+ return priv->fd_mapping ? priv->fd_mapping->len : 0;
+}
+
+gint
+ide_runner_get_nth_fd_maping (IdeRunner *self,
+ guint i,
+ gint *dest_fd)
+{
+ IdeRunnerPrivate *priv = ide_runner_get_instance_private (self);
+ FdMapping *map;
+
+ g_return_val_if_fail (IDE_IS_RUNNER (self), -1);
+ g_return_val_if_fail (priv->fd_mapping != NULL, -1);
+ g_return_val_if_fail (i < priv->fd_mapping->len, -1);
+ g_return_val_if_fail (dest_fd != NULL, -1);
+
+ map = &g_array_index (priv->fd_mapping, FdMapping, i);
+
+ *dest_fd = map->dest_fd;
+
+ return map->source_fd;
+}
diff --git a/libide/runner/ide-runner.h b/libide/runner/ide-runner.h
index d28ff82..8fa3e1b 100644
--- a/libide/runner/ide-runner.h
+++ b/libide/runner/ide-runner.h
@@ -73,6 +73,9 @@ void ide_runner_append_argv (IdeRunner *self,
gchar **ide_runner_get_argv (IdeRunner *self);
void ide_runner_set_argv (IdeRunner *self,
const gchar * const *argv);
+gint ide_runner_take_fd (IdeRunner *self,
+ gint source_fd,
+ gint dest_fd);
GInputStream *ide_runner_get_stdin (IdeRunner *self);
GOutputStream *ide_runner_get_stdout (IdeRunner *self);
GOutputStream *ide_runner_get_stderr (IdeRunner *self);
diff --git a/libide/subprocess/ide-breakout-subprocess-private.h
b/libide/subprocess/ide-breakout-subprocess-private.h
index 3ec8a4e..ef4c6af 100644
--- a/libide/subprocess/ide-breakout-subprocess-private.h
+++ b/libide/subprocess/ide-breakout-subprocess-private.h
@@ -23,16 +23,24 @@
G_BEGIN_DECLS
-IdeSubprocess *_ide_breakout_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,
- GCancellable *cancellable,
- GError **error) G_GNUC_INTERNAL;
+typedef struct
+{
+ gint source_fd;
+ gint dest_fd;
+} IdeBreakoutFdMapping;
+
+IdeSubprocess *_ide_breakout_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;
G_END_DECLS
diff --git a/libide/subprocess/ide-breakout-subprocess.c b/libide/subprocess/ide-breakout-subprocess.c
index 655482a..72cc435 100644
--- a/libide/subprocess/ide-breakout-subprocess.c
+++ b/libide/subprocess/ide-breakout-subprocess.c
@@ -36,6 +36,7 @@
#include "application/ide-application.h"
#include "subprocess/ide-breakout-subprocess.h"
+#include "subprocess/ide-breakout-subprocess-private.h"
#include "util/ide-glib.h"
#ifndef FLATPAK_HOST_COMMAND_FLAGS_CLEAR_ENV
@@ -82,6 +83,9 @@ struct _IdeBreakoutSubprocess
GInputStream *stdout_pipe;
GInputStream *stderr_pipe;
+ IdeBreakoutFdMapping *fd_mapping;
+ guint fd_mapping_len;
+
GMainContext *main_context;
guint sigint_id;
@@ -1350,6 +1354,33 @@ ide_breakout_subprocess_initable_init (GInitable *initable,
/*
+ * 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++)
+ {
+ const IdeBreakoutFdMapping *map = &self->fd_mapping[i];
+ g_autoptr(GError) fd_error = NULL;
+ gint dest_handle;
+
+ 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);
+
+ close (map->source_fd);
+ }
+
+ /*
+ * 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);
+
+
+ /*
* Build streams for our application to use.
*/
maybe_create_output_stream (&self->stdin_pipe, &stdin_pair[1], !!(self->flags &
G_SUBPROCESS_FLAGS_STDIN_PIPE));
@@ -1568,6 +1599,10 @@ ide_breakout_subprocess_finalize (GObject *object)
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_breakout_subprocess_parent_class)->finalize (object);
EGG_COUNTER_DEC (instances);
@@ -1697,16 +1732,18 @@ ide_breakout_subprocess_init (IdeBreakoutSubprocess *self)
}
IdeSubprocess *
-_ide_breakout_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,
- GCancellable *cancellable,
- GError **error)
+_ide_breakout_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)
{
g_autoptr(IdeBreakoutSubprocess) ret = NULL;
@@ -1725,6 +1762,10 @@ _ide_breakout_subprocess_new (const gchar *cwd,
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(gint) * fd_mapping_len);
+
if (!g_initable_init (G_INITABLE (ret), cancellable, error))
return NULL;
diff --git a/libide/subprocess/ide-subprocess-launcher.c b/libide/subprocess/ide-subprocess-launcher.c
index 6a1dd3e..2a4f797 100644
--- a/libide/subprocess/ide-subprocess-launcher.c
+++ b/libide/subprocess/ide-subprocess-launcher.c
@@ -43,6 +43,7 @@ typedef struct
GPtrArray *argv;
gchar *cwd;
gchar **environ;
+ GArray *fd_mapping;
gint stdin_fd;
gint stdout_fd;
@@ -52,6 +53,12 @@ typedef struct
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 {
@@ -175,6 +182,7 @@ 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;
IDE_ENTRY;
@@ -191,6 +199,8 @@ ide_subprocess_launcher_spawn_host_worker (GTask *task,
}
#endif
+ fds = g_steal_pointer (&priv->fd_mapping);
+
process = _ide_breakout_subprocess_new (priv->cwd,
(const gchar * const *)priv->argv->pdata,
(const gchar * const *)priv->environ,
@@ -199,6 +209,8 @@ ide_subprocess_launcher_spawn_host_worker (GTask *task,
priv->stdin_fd,
priv->stdout_fd,
priv->stderr_fd,
+ fds ? (gpointer)fds->data : NULL,
+ fds ? fds->len : 0,
cancellable,
&error);
@@ -280,6 +292,18 @@ ide_subprocess_launcher_spawn_worker (GTask *task,
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++)
+ {
+ const FdMapping *map = &g_array_index (ar, FdMapping, i);
+
+ g_subprocess_launcher_take_fd (launcher, map->source_fd, map->dest_fd);
+ }
+ }
+
/*
* GSubprocessLauncher starts by inheriting the current environment.
* So if clear-env is set, we need to unset those environment variables.
@@ -362,6 +386,19 @@ 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_pointer (&priv->argv, g_ptr_array_unref);
g_clear_pointer (&priv->cwd, g_free);
g_clear_pointer (&priv->environ, g_strfreev);
@@ -882,3 +919,24 @@ ide_subprocess_launcher_replace_argv (IdeSubprocessLauncher *self,
g_ptr_array_index (priv->argv, index) = g_strdup (arg);
g_free (old_arg);
}
+
+void
+ide_subprocess_launcher_take_fd (IdeSubprocessLauncher *self,
+ gint source_fd,
+ gint 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);
+}
diff --git a/libide/subprocess/ide-subprocess-launcher.h b/libide/subprocess/ide-subprocess-launcher.h
index 69b5f0e..ae0e437 100644
--- a/libide/subprocess/ide-subprocess-launcher.h
+++ b/libide/subprocess/ide-subprocess-launcher.h
@@ -86,6 +86,9 @@ gchar *ide_subprocess_launcher_pop_argv (IdeSubproces
IdeSubprocess *ide_subprocess_launcher_spawn (IdeSubprocessLauncher *self,
GCancellable *cancellable,
GError **error);
+void ide_subprocess_launcher_take_fd (IdeSubprocessLauncher *self,
+ gint source_fd,
+ gint dest_fd);
void ide_subprocess_launcher_take_stdin_fd (IdeSubprocessLauncher *self,
gint stdin_fd);
void ide_subprocess_launcher_take_stdout_fd (IdeSubprocessLauncher *self,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]