[glib/wip/subprocess-2013: 5/6] subprocess WIP
- From: Ryan Lortie <ryanl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/wip/subprocess-2013: 5/6] subprocess WIP
- Date: Mon, 21 Jan 2013 21:22:45 +0000 (UTC)
commit d8913abf3b05f701da53cbe39f661a68ffb4d217
Author: Ryan Lortie <desrt desrt ca>
Date: Fri Jan 18 13:01:11 2013 -0500
subprocess WIP
gio/Makefile.am | 6 +-
gio/gio.h | 2 +-
gio/gioenums.h | 26 +-
gio/giotypes.h | 4 +-
gio/gsubprocess.c | 234 +++++----
gio/gsubprocess.h | 68 ++--
gio/gsubprocesscontext.c | 307 -----------
gio/gsubprocesscontext.h | 118 -----
...ext-private.h => gsubprocesslauncher-private.h} | 22 +-
gio/gsubprocesslauncher.c | 536 ++++++++++++++++++++
gio/gsubprocesslauncher.h | 102 ++++
11 files changed, 824 insertions(+), 601 deletions(-)
---
diff --git a/gio/Makefile.am b/gio/Makefile.am
index fd0e4c0..57767d8 100644
--- a/gio/Makefile.am
+++ b/gio/Makefile.am
@@ -424,9 +424,9 @@ libgio_2_0_la_SOURCES = \
gsocketlistener.c \
gsocketoutputstream.c \
gsocketoutputstream.h \
+ gsubprocesslauncher.c \
gsubprocess.c \
- gsubprocesscontext.c \
- gsubprocesscontext-private.h \
+ gsubprocesslauncher-private.h \
gproxy.c \
gproxyaddress.c \
gproxyaddressenumerator.c \
@@ -592,7 +592,7 @@ gio_headers = \
gsrvtarget.h \
gtask.h \
gsubprocess.h \
- gsubprocesscontext.h \
+ gsubprocesslauncher.h \
gtcpconnection.h \
gtcpwrapperconnection.h \
gthreadedsocketservice.h\
diff --git a/gio/gio.h b/gio/gio.h
index f52e01b..45e9eff 100644
--- a/gio/gio.h
+++ b/gio/gio.h
@@ -124,7 +124,7 @@
#include <gio/gsrvtarget.h>
#include <gio/gtask.h>
#include <gio/gsubprocess.h>
-#include <gio/gsubprocesscontext.h>
+#include <gio/gsubprocesslauncher.h>
#include <gio/gtcpconnection.h>
#include <gio/gtcpwrapperconnection.h>
#include <gio/gtestdbus.h>
diff --git a/gio/gioenums.h b/gio/gioenums.h
index 53798aa..7b7dd6b 100644
--- a/gio/gioenums.h
+++ b/gio/gioenums.h
@@ -1659,23 +1659,25 @@ typedef enum /*< flags >*/ {
} GTestDBusFlags;
/**
- * GSubprocessStreamDisposition:
- * @G_SUBPROCESS_STREAM_DISPOSITION_NULL: Redirect to operating system's null output stream
- * @G_SUBPROCESS_STREAM_DISPOSITION_INHERIT: Keep the stream from the parent process
- * @G_SUBPROCESS_STREAM_DISPOSITION_PIPE: Open a private unidirectional channel between the processes
- * @G_SUBPROCESS_STREAM_DISPOSITION_STDERR_MERGE: Only applicable to standard error; causes it to be merged with standard output
+ * GSubprocessFlags:
+ * @G_SUBPROCESS_FLAGS_NONE: No flags.
*
- * Flags to define the behaviour of the standard input/output/error of
- * a #GSubprocess.
+ * Flags to define the behaviour of a #GSubprocess.
*
* Since: 2.36
**/
typedef enum {
- G_SUBPROCESS_STREAM_DISPOSITION_NULL,
- G_SUBPROCESS_STREAM_DISPOSITION_INHERIT,
- G_SUBPROCESS_STREAM_DISPOSITION_PIPE,
- G_SUBPROCESS_STREAM_DISPOSITION_STDERR_MERGE
-} GSubprocessStreamDisposition;
+ G_SUBPROCESS_FLAGS_NONE = 0,
+ G_SUBPROCESS_FLAGS_SEARCH_PATH = (1u << 0),
+ G_SUBPROCESS_FLAGS_SEARCH_PATH_FROM_ENVP = (1u << 1),
+ G_SUBPROCESS_FLAGS_STDIN_PIPE = (1u << 2),
+ G_SUBPROCESS_FLAGS_STDIN_INHERIT = (1u << 3),
+ G_SUBPROCESS_FLAGS_STDOUT_PIPE = (1u << 4),
+ G_SUBPROCESS_FLAGS_STDOUT_SILENCE = (1u << 5),
+ G_SUBPROCESS_FLAGS_STDERR_PIPE = (1u << 6),
+ G_SUBPROCESS_FLAGS_STDERR_SILENCE = (1u << 7),
+ G_SUBPROCESS_FLAGS_STDERR_MERGE = (1u << 8)
+} GSubprocessFlags;
G_END_DECLS
diff --git a/gio/giotypes.h b/gio/giotypes.h
index 30c6701..733bc48 100644
--- a/gio/giotypes.h
+++ b/gio/giotypes.h
@@ -478,13 +478,13 @@ typedef struct _GTestDBus GTestDBus;
*/
typedef struct _GSubprocess GSubprocess;
/**
- * GSubprocessContext:
+ * GSubprocessLauncher:
*
* Options for launching a child process.
*
* Since: 2.36
*/
-typedef struct _GSubprocessContext GSubprocessContext;
+typedef struct _GSubprocessLauncher GSubprocessLauncher;
G_END_DECLS
diff --git a/gio/gsubprocess.c b/gio/gsubprocess.c
index 8e70aaa..a2e4105 100644
--- a/gio/gsubprocess.c
+++ b/gio/gsubprocess.c
@@ -38,7 +38,7 @@
#include "config.h"
#include "gsubprocess.h"
-#include "gsubprocesscontext-private.h"
+#include "gsubprocesslauncher-private.h"
#include "gasyncresult.h"
#include "giostream.h"
#include "gmemoryinputstream.h"
@@ -77,7 +77,11 @@ struct _GSubprocess
{
GObject parent;
- GSubprocessContext *context;
+ /* only used during construction */
+ GSubprocessFlags flags;
+ gchar **argv;
+
+ GSubprocessLauncher *launcher;
GPid pid;
guint pid_valid : 1;
@@ -96,7 +100,8 @@ G_DEFINE_TYPE_WITH_CODE (GSubprocess, g_subprocess, G_TYPE_OBJECT,
enum
{
PROP_0,
- PROP_CONTEXT,
+ PROP_FLAGS,
+ PROP_ARGV,
N_PROPS
};
@@ -143,27 +148,12 @@ g_subprocess_set_property (GObject *object,
switch (prop_id)
{
- case PROP_CONTEXT:
- self->context = g_value_dup_object (value);
+ case PROP_FLAGS:
+ self->flags = g_value_get_flags (value);
break;
- default:
- g_assert_not_reached ();
- }
-}
-
-static void
-g_subprocess_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- GSubprocess *self = G_SUBPROCESS (object);
-
- switch (prop_id)
- {
- case PROP_CONTEXT:
- g_value_set_object (value, self->context);
+ case PROP_ARGV:
+ self->argv = g_value_dup_boxed (value);
break;
default:
@@ -177,18 +167,14 @@ g_subprocess_class_init (GSubprocessClass *class)
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
gobject_class->finalize = g_subprocess_finalize;
- gobject_class->get_property = g_subprocess_get_property;
gobject_class->set_property = g_subprocess_set_property;
- /**
- * GSubprocess:context:
- *
- *
- * Since: 2.36
- */
- g_subprocess_pspecs[PROP_CONTEXT] = g_param_spec_object ("context", P_("Context"), P_("Subprocess options"), G_TYPE_SUBPROCESS_CONTEXT,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS);
+ g_subprocess_pspecs[PROP_FLAGS] = g_param_spec_flags ("flags", P_("Flags"), P_("Subprocess flags"),
+ G_TYPE_SUBPROCESS_FLAGS, 0, G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+ g_subprocess_pspecs[PROP_ARGV] = g_param_spec_boxed ("argv", P_("Arguments"), P_("Argument vector"),
+ G_TYPE_STRV, G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, N_PROPS, g_subprocess_pspecs);
}
@@ -326,92 +312,79 @@ initable_init (GInitable *initable,
*
* First, stdin.
*/
+ if (self->flags & G_SUBPROCESS_FLAGS_STDIN_INHERIT)
+ spawn_flags |= G_SPAWN_CHILD_INHERITS_STDIN;
+ else if (self->flags & G_SUBPROCESS_FLAGS_STDIN_PIPE)
+ pipe_ptrs[0] = &pipe_fds[0];
#ifdef G_OS_UNIX
- if (self->context->stdin_fd != -1)
- child_data.fds[0] = self->context->stdin_fd;
- else if (self->context->stdin_path != NULL)
+ else if (self->launcher)
{
- child_data.fds[0] = close_fds[0] = unix_open_file (self->context->stdin_path,
- O_RDONLY, error);
- if (child_data.fds[0] == -1)
- goto out;
+ if (self->launcher->stdin_fd != -1)
+ child_data.fds[0] = self->launcher->stdin_fd;
+ else if (self->launcher->stdin_path != NULL)
+ {
+ child_data.fds[0] = close_fds[0] = unix_open_file (self->launcher->stdin_path, O_RDONLY, error);
+ if (child_data.fds[0] == -1)
+ goto out;
+ }
}
- else
#endif
- if (self->context->stdin_disposition == G_SUBPROCESS_STREAM_DISPOSITION_NULL)
- ; /* nothing */
- else if (self->context->stdin_disposition == G_SUBPROCESS_STREAM_DISPOSITION_INHERIT)
- spawn_flags |= G_SPAWN_CHILD_INHERITS_STDIN;
- else if (self->context->stdin_disposition == G_SUBPROCESS_STREAM_DISPOSITION_PIPE)
- pipe_ptrs[0] = &pipe_fds[0];
- else
- g_assert_not_reached ();
/* Next, stdout. */
+ if (self->flags & G_SUBPROCESS_FLAGS_STDOUT_SILENCE)
+ spawn_flags |= G_SPAWN_STDOUT_TO_DEV_NULL;
+ else if (self->flags & G_SUBPROCESS_FLAGS_STDOUT_PIPE)
+ pipe_ptrs[1] = &pipe_fds[1];
#ifdef G_OS_UNIX
- if (self->context->stdout_fd != -1)
- child_data.fds[1] = self->context->stdout_fd;
- else if (self->context->stdout_path != NULL)
+ else if (self->launcher)
{
- child_data.fds[1] = close_fds[1] = unix_open_file (self->context->stdout_path,
- O_CREAT | O_WRONLY, error);
- if (child_data.fds[1] == -1)
- goto out;
+ if (self->launcher->stdout_fd != -1)
+ child_data.fds[1] = self->launcher->stdout_fd;
+ else if (self->launcher->stdout_path != NULL)
+ {
+ child_data.fds[1] = close_fds[1] = unix_open_file (self->launcher->stdout_path,
+ O_CREAT | O_WRONLY, error);
+ if (child_data.fds[1] == -1)
+ goto out;
+ }
}
- else
#endif
- if (self->context->stdout_disposition == G_SUBPROCESS_STREAM_DISPOSITION_NULL)
- spawn_flags |= G_SPAWN_STDOUT_TO_DEV_NULL;
- else if (self->context->stdout_disposition == G_SUBPROCESS_STREAM_DISPOSITION_INHERIT)
- ; /* Nothing */
- else if (self->context->stdout_disposition == G_SUBPROCESS_STREAM_DISPOSITION_PIPE)
- pipe_ptrs[1] = &pipe_fds[1];
- else
- g_assert_not_reached ();
/* Finally, stderr. */
+ if (self->flags & G_SUBPROCESS_FLAGS_STDERR_SILENCE)
+ spawn_flags |= G_SPAWN_STDERR_TO_DEV_NULL;
+ else if (self->flags & G_SUBPROCESS_FLAGS_STDERR_PIPE)
+ pipe_ptrs[2] = &pipe_fds[2];
#ifdef G_OS_UNIX
- if (self->context->stderr_fd != -1)
- child_data.fds[2] = self->context->stderr_fd;
- else if (self->context->stderr_path != NULL)
+ if (self->launcher)
{
- child_data.fds[2] = close_fds[2] = unix_open_file (self->context->stderr_path,
- O_CREAT | O_WRONLY, error);
- if (child_data.fds[2] == -1)
- goto out;
+ if (self->launcher->stderr_fd != -1)
+ child_data.fds[2] = self->launcher->stderr_fd;
+ else if (self->launcher->stderr_path != NULL)
+ {
+ child_data.fds[2] = close_fds[2] = unix_open_file (self->launcher->stderr_path,
+ O_CREAT | O_WRONLY, error);
+ if (child_data.fds[2] == -1)
+ goto out;
+ }
}
- else
#endif
- if (self->context->stderr_disposition == G_SUBPROCESS_STREAM_DISPOSITION_NULL)
- spawn_flags |= G_SPAWN_STDERR_TO_DEV_NULL;
- else if (self->context->stderr_disposition == G_SUBPROCESS_STREAM_DISPOSITION_INHERIT)
- ; /* Nothing */
- else if (self->context->stderr_disposition == G_SUBPROCESS_STREAM_DISPOSITION_PIPE)
- pipe_ptrs[2] = &pipe_fds[2];
- else if (self->context->stderr_disposition == G_SUBPROCESS_STREAM_DISPOSITION_STDERR_MERGE)
- /* This will work because stderr gets setup after stdout. */
- child_data.fds[2] = 1;
- else
- g_assert_not_reached ();
-
- if (self->context->keep_descriptors)
- spawn_flags |= G_SPAWN_LEAVE_DESCRIPTORS_OPEN;
- if (self->context->search_path)
+ if (self->flags & G_SUBPROCESS_FLAGS_SEARCH_PATH)
spawn_flags |= G_SPAWN_SEARCH_PATH;
- else if (self->context->search_path_from_envp)
+
+ else if (self->flags & G_SUBPROCESS_FLAGS_SEARCH_PATH_FROM_ENVP)
spawn_flags |= G_SPAWN_SEARCH_PATH_FROM_ENVP;
- else if (!g_path_is_absolute (((gchar**)self->context->argv->pdata)[0]))
- spawn_flags |= G_SPAWN_SEARCH_PATH;
+ spawn_flags |= G_SPAWN_LEAVE_DESCRIPTORS_OPEN;
spawn_flags |= G_SPAWN_DO_NOT_REAP_CHILD;
spawn_flags |= G_SPAWN_CLOEXEC_PIPES;
- child_data.child_setup_func = self->context->child_setup_func;
- child_data.child_setup_data = self->context->child_setup_data;
- success = g_spawn_async_with_pipes (self->context->cwd,
- (char**)self->context->argv->pdata,
- self->context->envp,
+ child_data.child_setup_func = self->launcher ? self->launcher->child_setup_func : NULL;
+ child_data.child_setup_data = self->launcher ? self->launcher->child_setup_user_data : NULL;
+ success = g_spawn_async_with_pipes (self->launcher ? self->launcher->cwd : NULL,
+ self->argv,
+ self->launcher ? self->launcher->envp : NULL,
spawn_flags,
child_setup, &child_data,
&self->pid,
@@ -439,23 +412,66 @@ initable_iface_init (GInitableIface *initable_iface)
}
/**
- * g_subprocess_new:
+ * g_subprocess_new: (skip)
+ *
+ * Create a new process with the given flags and varargs argument list.
+ *
+ * The argument list must be terminated with %NULL.
+ *
+ * Returns: A newly created #GSubprocess, or %NULL on error (and @error
+ * will be set)
+ *
+ * Since: 2.36
+ */
+GSubprocess *
+g_subprocess_new (GSubprocessFlags flags,
+ GError **error,
+ const gchar *argv0,
+ ...)
+{
+ GSubprocess *result;
+ GPtrArray *args;
+ const gchar *arg;
+ va_list ap;
+
+ g_return_val_if_fail (argv0 != NULL, NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ args = g_ptr_array_new ();
+
+ va_start (ap, argv0);
+ g_ptr_array_add (args, (gchar *) argv0);
+ while ((arg = va_arg (ap, const gchar *)))
+ g_ptr_array_add (args, (gchar *) arg);
+
+ result = g_subprocess_newv ((const gchar * const *) args->pdata, flags, error);
+
+ g_ptr_array_free (args, TRUE);
+
+ return result;
+}
+
+/**
+ * g_subprocess_newv:
+ *
+ * Create a new process with the given flags and argument list.
*
- * Create a new process, using the parameters specified by
- * GSubprocessContext.
+ * The argument list is expected to be %NULL-terminated.
*
- * Returns: (transfer full): A newly created %GSubprocess, or %NULL on error (and @error will be set)
+ * Returns: A newly created #GSubprocess, or %NULL on error (and @error
+ * will be set)
*
* Since: 2.36
+ * Rename to: g_subprocess_new
*/
-GLIB_AVAILABLE_IN_2_36
GSubprocess *
-g_subprocess_new (GSubprocessContext *context,
- GError **error)
+g_subprocess_newv (const gchar * const *argv,
+ GSubprocessFlags flags,
+ GError **error)
{
- return g_initable_new (G_TYPE_SUBPROCESS,
- NULL, error,
- "context", context,
+ return g_initable_new (G_TYPE_SUBPROCESS, NULL, error,
+ "argv", argv,
+ "flags", flags,
NULL);
}
@@ -566,10 +582,10 @@ g_subprocess_on_child_exited (GPid pid,
* Since: 2.36
*/
void
-g_subprocess_wait (GSubprocess *self,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+g_subprocess_wait_async (GSubprocess *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
GSource *source;
GSubprocessWatchData *data;
diff --git a/gio/gsubprocess.h b/gio/gsubprocess.h
index 2af5363..acd29a2 100644
--- a/gio/gsubprocess.h
+++ b/gio/gsubprocess.h
@@ -36,68 +36,68 @@ G_BEGIN_DECLS
#define G_IS_SUBPROCESS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_SUBPROCESS))
GLIB_AVAILABLE_IN_2_36
-GType g_subprocess_get_type (void) G_GNUC_CONST;
+GType g_subprocess_get_type (void) G_GNUC_CONST;
/**** Core API ****/
GLIB_AVAILABLE_IN_2_36
-GSubprocess * g_subprocess_new (GSubprocessContext *context,
- GError **error);
+GSubprocess * g_subprocess_new (GSubprocessFlags flags,
+ GError **error,
+ const gchar *argv0,
+ ...) G_GNUC_NULL_TERMINATED;
+GLIB_AVAILABLE_IN_2_36
+GSubprocess * g_subprocess_newv (const gchar * const *argv,
+ GSubprocessFlags flags,
+ GError **error);
GLIB_AVAILABLE_IN_2_36
-GOutputStream * g_subprocess_get_stdin_pipe (GSubprocess *self);
+GOutputStream * g_subprocess_get_stdin_pipe (GSubprocess *self);
GLIB_AVAILABLE_IN_2_36
-GInputStream * g_subprocess_get_stdout_pipe (GSubprocess *self);
+GInputStream * g_subprocess_get_stdout_pipe (GSubprocess *self);
GLIB_AVAILABLE_IN_2_36
-GInputStream * g_subprocess_get_stderr_pipe (GSubprocess *self);
+GInputStream * g_subprocess_get_stderr_pipe (GSubprocess *self);
GLIB_AVAILABLE_IN_2_36
-void g_subprocess_wait (GSubprocess *self,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
+GPid g_subprocess_get_pid (GSubprocess *self);
GLIB_AVAILABLE_IN_2_36
-gboolean g_subprocess_wait_finish (GSubprocess *self,
- GAsyncResult *result,
- int *out_exit_status,
- GError **error);
+void g_subprocess_request_exit (GSubprocess *self);
GLIB_AVAILABLE_IN_2_36
-gboolean g_subprocess_wait_sync (GSubprocess *self,
- int *out_exit_status,
- GCancellable *cancellable,
- GError **error);
+void g_subprocess_force_exit (GSubprocess *self);
GLIB_AVAILABLE_IN_2_36
-gboolean g_subprocess_wait_sync_check (GSubprocess *self,
- GCancellable *cancellable,
- GError **error);
+gboolean g_subprocess_wait (GSubprocess *self,
+ GCancellable *cancellable,
+ GError **error);
GLIB_AVAILABLE_IN_2_36
-GPid g_subprocess_get_pid (GSubprocess *self);
+void g_subprocess_wait_async (GSubprocess *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
GLIB_AVAILABLE_IN_2_36
-gboolean g_subprocess_request_exit (GSubprocess *self);
+gboolean g_subprocess_wait_finish (GSubprocess *self,
+ GAsyncResult *result,
+ GError **error);
GLIB_AVAILABLE_IN_2_36
-void g_subprocess_force_exit (GSubprocess *self);
+gboolean g_subprocess_get_successful (GSubprocess *self);
-/** High level helpers **/
+GLIB_AVAILABLE_IN_2_36
+gboolean g_subprocess_get_if_exited (GSubprocess *self);
GLIB_AVAILABLE_IN_2_36
-GSubprocess * g_subprocess_new_simple_argl (GSubprocessStreamDisposition stdout_disposition,
- GSubprocessStreamDisposition stderr_disposition,
- GError **error,
- const char *first_arg,
- ...) G_GNUC_NULL_TERMINATED;
+gint g_subprocess_get_exit_status (GSubprocess *self);
+
+GLIB_AVAILABLE_IN_2_36
+gboolean g_subprocess_get_if_signaled (GSubprocess *self);
+
GLIB_AVAILABLE_IN_2_36
-GSubprocess * g_subprocess_new_simple_argv (char **argv,
- GSubprocessStreamDisposition stdout_disposition,
- GSubprocessStreamDisposition stderr_disposition,
- GError **error);
+gint g_subprocess_get_term_signal (GSubprocess *self);
G_END_DECLS
diff --git a/gio/gsubprocesscontext-private.h b/gio/gsubprocesslauncher-private.h
similarity index 73%
rename from gio/gsubprocesscontext-private.h
rename to gio/gsubprocesslauncher-private.h
index 39ceafa..812722f 100644
--- a/gio/gsubprocesscontext-private.h
+++ b/gio/gsubprocesslauncher-private.h
@@ -21,29 +21,19 @@
#ifndef __G_SUBPROCESS_CONTEXT_PRIVATE_H__
#define __G_SUBPROCESS_CONTEXT_PRIVATE_H__
-#include "gsubprocesscontext.h"
+#include "gsubprocesslauncher.h"
G_BEGIN_DECLS
-struct _GSubprocessContext
+struct _GSubprocessLauncher
{
GObject parent;
- GSpawnFlags flags;
- GPtrArray *argv;
- gboolean has_argv0;
+ GSubprocessFlags flags;
char **envp;
char *cwd;
- GSubprocessStreamDisposition stdin_disposition;
- GSubprocessStreamDisposition stdout_disposition;
- GSubprocessStreamDisposition stderr_disposition;
-
- guint keep_descriptors : 1;
- guint search_path : 1;
- guint search_path_from_envp : 1;
- guint unused_flags : 29;
-
+#ifdef G_OS_UNIX
gint stdin_fd;
gchar *stdin_path;
@@ -54,7 +44,9 @@ struct _GSubprocessContext
gchar *stderr_path;
GSpawnChildSetupFunc child_setup_func;
- gpointer child_setup_data;
+ gpointer child_setup_user_data;
+ GDestroyNotify child_setup_destroy_notify;
+#endif
};
G_END_DECLS
diff --git a/gio/gsubprocesslauncher.c b/gio/gsubprocesslauncher.c
new file mode 100644
index 0000000..9ebb9e8
--- /dev/null
+++ b/gio/gsubprocesslauncher.c
@@ -0,0 +1,536 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright  2012 Red Hat, Inc.
+ * Copyright  2012 Canonical Limited
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the licence or (at
+ * your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Authors: Colin Walters <walters verbum org>
+ * Ryan Lortie <desrt desrt ca>
+ */
+
+/**
+ * SECTION:gsubprocess
+ * @title: GSubprocess Launcher
+ * @short_description: Environment options for launching a child process
+ *
+ * This class contains a set of options for launching child processes,
+ * such as where its standard input and output will be directed, the
+ * argument list, the environment, and more.
+ *
+ * While the #GSubprocess class has high level functions covering
+ * popular cases, use of this class allows access to more advanced
+ * options. It can also be used to launch multiple subprocesses with
+ * a similar configuration.
+ *
+ * Since: 2.36
+ */
+
+#define ALL_STDIN_FLAGS (G_SUBPROCESS_FLAGS_STDIN_PIPE | \
+ G_SUBPROCESS_FLAGS_STDIN_INHERIT)
+#define ALL_STDOUT_FLAGS (G_SUBPROCESS_FLAGS_STDOUT_PIPE | \
+ G_SUBPROCESS_FLAGS_STDOUT_SILENCE)
+#define ALL_STDERR_FLAGS (G_SUBPROCESS_FLAGS_STDERR_PIPE | \
+ G_SUBPROCESS_FLAGS_STDERR_SILENCE | \
+ G_SUBPROCESS_FLAGS_STDERR_MERGE)
+
+#include "config.h"
+
+#include "gsubprocesslauncher-private.h"
+#include "gioenumtypes.h"
+
+typedef GObjectClass GSubprocessLauncherClass;
+
+G_DEFINE_TYPE (GSubprocessLauncher, g_subprocess_launcher, G_TYPE_OBJECT);
+
+static void
+g_subprocess_launcher_finalize (GObject *object)
+{
+ GSubprocessLauncher *self = G_SUBPROCESS_LAUNCHER (object);
+
+ g_strfreev (self->envp);
+ g_free (self->cwd);
+
+ g_free (self->stdin_path);
+ g_free (self->stdout_path);
+ g_free (self->stderr_path);
+
+ if (self->child_setup_destroy_notify)
+ (* self->child_setup_destroy_notify) (self->child_setup_user_data);
+
+ if (G_OBJECT_CLASS (g_subprocess_launcher_parent_class)->finalize != NULL)
+ G_OBJECT_CLASS (g_subprocess_launcher_parent_class)->finalize (object);
+}
+
+static void
+g_subprocess_launcher_init (GSubprocessLauncher *self)
+{
+ self->envp = g_listenv ();
+
+ self->stdin_fd = -1;
+ self->stdout_fd = -1;
+ self->stderr_fd = -1;
+}
+
+static void
+g_subprocess_launcher_class_init (GSubprocessLauncherClass *class)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+
+ gobject_class->finalize = g_subprocess_launcher_finalize;
+}
+
+/**
+ * g_subprocess_launcher_new:
+ *
+ * Creates a new #GSubprocessLauncher.
+ *
+ * The launcher is created with the default options. A copy of the
+ * environment of the calling process is made at the time of this call
+ * and will be used as the environment that the process is launched in.
+ *
+ * Since: 2.36
+ **/
+GSubprocessLauncher *
+g_subprocess_launcher_new (void)
+{
+ return g_object_new (G_TYPE_SUBPROCESS_LAUNCHER, NULL);
+}
+
+
+/**
+ * g_subprocess_launcher_set_environ:
+ * @self: a #GSubprocess
+ * @environ: the replacement environment
+ *
+ * Replace the entire environment of processes launched from this
+ * launcher with the given 'environ' variable.
+ *
+ * Typically you will build this variable by using g_listenv() to copy
+ * the process 'environ' and using the functions g_environ_setenv(),
+ * g_environ_unsetenv(), etc.
+ *
+ * As an alternative, you can use g_subprocess_launcher_setenv(),
+ * g_subprocess_launcher_unsetenv(), etc.
+ *
+ * All strings in this array are expected to be in the GLib file name
+ * encoding. On UNIX, this means that they can be arbitrary byte
+ * strings. On Windows, they should be in UTF-8.
+ *
+ * Since: 2.36
+ **/
+void
+g_subprocess_launcher_set_environ (GSubprocessLauncher *self,
+ gchar **environ)
+{
+ g_strfreev (self->envp);
+ self->envp = g_strdupv (environ);
+}
+
+/**
+ * g_subprocess_launcher_setenv:
+ * @self: a #GSubprocess
+ * @variable: the environment variable to set, must not contain '='
+ * @value: the new value for the variable
+ * @overwrite: whether to change the variable if it already exists
+ *
+ * Sets the environment variable @variable in the environment of
+ * processes launched from this launcher.
+ *
+ * Both the variable's name and value should be in the GLib file name
+ * encoding. On UNIX, this means that they can be arbitrary byte
+ * strings. On Windows, they should be in UTF-8.
+ *
+ *
+ * Since: 2.36
+ **/
+void
+g_subprocess_launcher_setenv (GSubprocessLauncher *self,
+ const gchar *variable,
+ const gchar *value,
+ gboolean overwrite)
+{
+ self->envp = g_environ_setenv (self->envp, variable, value, overwrite);
+}
+
+/**
+ * g_subprocess_launcher_unsetsenv:
+ * @self: a #GSubprocess
+ * @variable: the environment variable to unset, must not contain '='
+ *
+ * Removes the environment variable @variable from the environment of
+ * processes launched from this launcher.
+ *
+ * The variable name should be in the GLib file name encoding. On UNIX,
+ * this means that they can be arbitrary byte strings. On Windows, they
+ * should be in UTF-8.
+ *
+ * Since: 2.36
+ **/
+void
+g_subprocess_launcher_unsetenv (GSubprocessLauncher *self,
+ const gchar *variable)
+{
+ self->envp = g_environ_unsetenv (self->envp, variable);
+}
+
+/**
+ * g_subprocess_launcher_getenv:
+ * @self: a #GSubprocess
+ * @variable: the environment variable to get
+ *
+ * Returns the value of the environment variable @variable in the
+ * environment of processes launched from this launcher.
+ *
+ * The returned string is in the GLib file name encoding. On UNIX, this
+ * means that it can be an arbitrary byte string. On Windows, it will
+ * be UTF-8.
+ *
+ * Returns: the value of the environment variable, %NULL if unset
+ *
+ * Since: 2.36
+ **/
+const gchar *
+g_subprocess_launcher_getenv (GSubprocessLauncher *self,
+ const gchar *variable)
+{
+ return g_environ_getenv (self->envp, variable);
+}
+
+/**
+ * g_subprocess_launcher_set_cwd:
+ * @self: a #GSubprocess
+ * @cwd: the cwd for launched processes
+ *
+ * Sets the current working directory that processes will be launched
+ * with.
+ *
+ * By default processes are launched with the current working directory
+ * of the launching process at the time of launch.
+ *
+ * Since: 2.36
+ **/
+void
+g_subprocess_launcher_set_cwd (GSubprocessLauncher *self,
+ const gchar *cwd)
+{
+ g_free (self->cwd);
+ self->cwd = g_strdup (cwd);
+}
+
+static gboolean
+verify_disposition (const gchar *stream_name,
+ GSubprocessFlags filtered_flags,
+ gint fd,
+ const gchar *filename)
+{
+ guint n_bits;
+
+ if (!filtered_flags)
+ n_bits = 0;
+ else if (((filtered_flags - 1) & filtered_flags) == 0)
+ n_bits = 1;
+ else
+ n_bits = 2; /* ...or more */
+
+ if (n_bits + (fd >= 0) + (filename != NULL) > 1)
+ {
+ GString *err;
+
+ err = g_string_new (NULL);
+ if (n_bits)
+ {
+ GFlagsClass *class;
+ GFlagsValue *value;
+
+ class = g_type_class_peek (G_TYPE_SUBPROCESS_FLAGS);
+ while ((value = g_flags_get_first_value (class, filtered_flags)))
+ {
+ g_string_append_printf (err, " %s", value->value_name);
+ filtered_flags &= value->value;
+ }
+
+ g_type_class_unref (class);
+ }
+
+ if (fd >= 0)
+ g_string_append_printf (err, " g_subprocess_launcher_set_%s_fd()", stream_name);
+
+ if (filename)
+ g_string_append_printf (err, " g_subprocess_launcher_set_%s_file_path()", stream_name);
+
+ g_critical ("You may specify at most one disposition for the %s stream, but you specified:%s.",
+ stream_name, err->str);
+ g_string_free (err, TRUE);
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * g_subprocess_launcher_set_flags:
+ * @self: a #GSubprocessLauncher
+ * @flags: #GSubprocessFlags
+ *
+ * Sets the flags on the launcher.
+ *
+ * The default flags are %G_SUBPROCESS_FLAGS_NONE.
+ *
+ * You may not set flags that specify conflicting options for how to
+ * handle a particular stdio stream (eg: specifying both
+ * %G_SUBPROCESS_FLAGS_STDIN_PIPE and
+ * %G_SUBPROCESS_FLAGS_STDIN_INHERIT).
+ *
+ * You may also not set a flag that conflicts with a previous call to a
+ * function like g_subprocess_launcher_set_stdin_file_path() or
+ * g_subprocess_launcher_set_stdout_fd().
+ *
+ * Since: 2.36
+ **/
+void
+g_subprocess_launcher_set_flags (GSubprocessLauncher *self,
+ GSubprocessFlags flags)
+{
+ if (verify_disposition ("stdin", flags & ALL_STDIN_FLAGS, self->stdin_fd, self->stdin_path) &&
+ verify_disposition ("stdout", flags & ALL_STDOUT_FLAGS, self->stdout_fd, self->stdout_path) &&
+ verify_disposition ("stderr", flags & ALL_STDERR_FLAGS, self->stderr_fd, self->stderr_path))
+ self->flags = flags;
+}
+
+#ifdef G_OS_UNIX
+/**
+ * g_subprocess_launcher_set_stdin_file_path:
+ * @self: a #GSubprocessLauncher
+ * @path: a filename or %NULL
+ *
+ * Sets the file path to use as the stdin for spawned processes.
+ *
+ * If @path is %NULL then any previously given path is unset.
+ *
+ * The file must exist or spawning the process will fail.
+ *
+ * You may not set a stdin file path if a stdin fd is already set or if
+ * the launcher flags contain any flags directing stdin elsewhere.
+ *
+ * This feature is only available on UNIX.
+ *
+ * Since: 2.36
+ **/
+void
+g_subprocess_launcher_set_stdin_file_path (GSubprocessLauncher *self,
+ const gchar *path)
+{
+ if (verify_disposition ("stdin", self->flags & ALL_STDIN_FLAGS, self->stdin_fd, path))
+ {
+ g_free (self->stdin_path);
+ self->stdin_path = g_strdup (path);
+ }
+}
+
+/**
+ * g_subprocess_launcher_set_stdin_fd:
+ * @self: a #GSubprocessLauncher
+ * @fd: a file descriptor, or -1
+ *
+ * Sets the file descriptor to use as the stdin for spawned processes.
+ *
+ * If @fd is -1 then any previously given fd is unset.
+ *
+ * Note that if your intention is to have the stdin of the calling
+ * process inherited by the child then %G_SUBPROCESS_FLAGS_STDIN_INHERIT
+ * is a better way to go about doing that.
+ *
+ * The passed @fd is noted but will not be touched in the current
+ * process. It is therefore necessary that it be kept open by the
+ * caller until the subprocess is spawned. The file descriptor will
+ * also not be explicitly closed on the child side, so it must be marked
+ * O_CLOEXEC if that's what you want.
+ *
+ * You may not set a stdin fd if a stdin file path is already set or if
+ * the launcher flags contain any flags directing stdin elsewhere.
+ *
+ * This feature is only available on UNIX.
+ *
+ * Since: 2.36
+ **/
+void
+g_subprocess_launcher_set_stdin_fd (GSubprocessLauncher *self,
+ gint fd)
+{
+ if (verify_disposition ("stdin", self->flags & ALL_STDIN_FLAGS, fd, self->stdin_path))
+ self->stdin_fd = fd;
+}
+
+/**
+ * g_subprocess_launcher_set_stdout_file_path:
+ * @self: a #GSubprocessLauncher
+ * @path: a filename or %NULL
+ *
+ * Sets the file path to use as the stdout for spawned processes.
+ *
+ * If @path is %NULL then any previously given path is unset.
+ *
+ * The file will be created or truncated when the process is spawned, as
+ * would be the case if using '>' at the shell.
+ *
+ * You may not set a stdout file path if a stdout fd is already set or
+ * if the launcher flags contain any flags directing stdout elsewhere.
+ *
+ * This feature is only available on UNIX.
+ *
+ * Since: 2.36
+ **/
+void
+g_subprocess_launcher_set_stdout_file_path (GSubprocessLauncher *self,
+ const gchar *path)
+{
+ if (verify_disposition ("stdout", self->flags & ALL_STDIN_FLAGS, self->stdout_fd, path))
+ {
+ g_free (self->stdout_path);
+ self->stdout_path = g_strdup (path);
+ }
+}
+
+/**
+ * g_subprocess_launcher_set_stdout_fd:
+ * @self: a #GSubprocessLauncher
+ * @fd: a file descriptor, or -1
+ *
+ * Sets the file descriptor to use as the stdout for spawned processes.
+ *
+ * If @fd is -1 then any previously given fd is unset.
+ *
+ * Note that the default behaviour is to pass stdout through to the
+ * stdout of the parent process.
+ *
+ * The passed @fd is noted but will not be touched in the current
+ * process. It is therefore necessary that it be kept open by the
+ * caller until the subprocess is spawned. The file descriptor will
+ * also not be explicitly closed on the child side, so it must be marked
+ * O_CLOEXEC if that's what you want.
+ *
+ * You may not set a stdout fd if a stdout file path is already set or
+ * if the launcher flags contain any flags directing stdout elsewhere.
+ *
+ * This feature is only available on UNIX.
+ *
+ * Since: 2.36
+ **/
+void
+g_subprocess_launcher_set_stdout_fd (GSubprocessLauncher *self,
+ gint fd)
+{
+ if (verify_disposition ("stdin", self->flags & ALL_STDIN_FLAGS, fd, self->stdin_path))
+ self->stdout_fd = fd;
+}
+
+/**
+ * g_subprocess_launcher_set_stderr_file_path:
+ * @self: a #GSubprocessLauncher
+ * @path: a filename or %NULL
+ *
+ * Sets the file path to use as the stderr for spawned processes.
+ *
+ * If @path is %NULL then any previously given path is unset.
+ *
+ * The file will be created or truncated when the process is spawned, as
+ * would be the case if using '2>' at the shell.
+ *
+ * If you want to send both stdout and stderr to the same file then use
+ * %G_SUBPROCESS_FLAGS_STDERR_MERGE.
+ *
+ * You may not set a stderr file path if a stderr fd is already set or
+ * if the launcher flags contain any flags directing stderr elsewhere.
+ *
+ * This feature is only available on UNIX.
+ *
+ * Since: 2.36
+ **/
+void
+g_subprocess_launcher_set_stderr_file_path (GSubprocessLauncher *self,
+ const gchar *path)
+{
+ if (verify_disposition ("stderr", self->flags & ALL_STDIN_FLAGS, self->stderr_fd, path))
+ {
+ g_free (self->stderr_path);
+ self->stderr_path = g_strdup (path);
+ }
+}
+
+/**
+ * g_subprocess_launcher_set_stderr_fd:
+ * @self: a #GSubprocessLauncher
+ * @fd: a file descriptor, or -1
+ *
+ * Sets the file descriptor to use as the stderr for spawned processes.
+ *
+ * If @fd is -1 then any previously given fd is unset.
+ *
+ * Note that the default behaviour is to pass stderr through to the
+ * stderr of the parent process.
+ *
+ * The passed @fd is noted but will not be touched in the current
+ * process. It is therefore necessary that it be kept open by the
+ * caller until the subprocess is spawned. The file descriptor will
+ * also not be explicitly closed on the child side, so it must be marked
+ * O_CLOEXEC if that's what you want.
+ *
+ * You may not set a stderr fd if a stderr file path is already set or
+ * if the launcher flags contain any flags directing stderr elsewhere.
+ *
+ * This feature is only available on UNIX.
+ *
+ * Since: 2.36
+ **/
+void
+g_subprocess_launcher_set_stderr_fd (GSubprocessLauncher *self,
+ gint fd)
+{
+ if (verify_disposition ("stdin", self->flags & ALL_STDIN_FLAGS, fd, self->stdin_path))
+ self->stderr_fd = fd;
+}
+
+/**
+ * g_subprocess_launcher_set_child_setup:
+ * @self: a #GSubprocessLauncher
+ * @child_setup: a #GSpawnChildSetupFunc to use as the child setup function
+ * @user_data: user data for @child_setup
+ * @destroy_notify: a #GDestroyNotify for @user_data
+ *
+ * Sets up a child setup function.
+ *
+ * The child setup function will be called after fork() but before
+ * exec() on the child's side.
+ *
+ * @destroy_notify will not be automatically called on the child's side
+ * of the fork(). It will only be called when the last reference on the
+ * #GSubprocessLauncher is dropped or when a new child setup function is
+ * given.
+ *
+ * %NULL can be given as @child_setup to disable the functionality.
+ *
+ * Child setup functions are only available on UNIX.
+ *
+ * Since: 2.36
+ **/
+void
+g_subprocess_launcher_set_child_setup (GSubprocessLauncher *self,
+ GSpawnChildSetupFunc child_setup,
+ gpointer user_data,
+ GDestroyNotify destroy_notify)
+{
+ if (self->child_setup_destroy_notify)
+ (* self->child_setup_destroy_notify) (self->child_setup_user_data);
+
+ self->child_setup_func = child_setup;
+ self->child_setup_user_data = user_data;
+ self->child_setup_destroy_notify = destroy_notify;
+}
+#endif
diff --git a/gio/gsubprocesslauncher.h b/gio/gsubprocesslauncher.h
new file mode 100644
index 0000000..642f8bc
--- /dev/null
+++ b/gio/gsubprocesslauncher.h
@@ -0,0 +1,102 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright  2012 Colin Walters <walters verbum org>
+ * Copyright  2012 Canonical Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Ryan Lortie <desrt desrt ca>
+ * Author: Colin Walters <walters verbum org>
+ */
+
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#ifndef __G_SUBPROCESS_LAUNCHER_H__
+#define __G_SUBPROCESS_LAUNCHER_H__
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_SUBPROCESS_LAUNCHER (g_subprocess_launcher_get_type ())
+#define G_SUBPROCESS_LAUNCHER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_SUBPROCESS_LAUNCHER, GSubprocessLauncher))
+#define G_IS_SUBPROCESS_LAUNCHER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_SUBPROCESS_LAUNCHER))
+
+GLIB_AVAILABLE_IN_2_36
+GType g_subprocess_launcher_get_type (void) G_GNUC_CONST;
+
+GLIB_AVAILABLE_IN_2_36
+GSubprocessLauncher * g_subprocess_launcher_new (void);
+
+GLIB_AVAILABLE_IN_2_36
+void g_subprocess_launcher_set_environ (GSubprocessLauncher *self,
+ gchar **environ);
+
+GLIB_AVAILABLE_IN_2_36
+void g_subprocess_launcher_setenv (GSubprocessLauncher *self,
+ const gchar *variable,
+ const gchar *value,
+ gboolean overwrite);
+
+GLIB_AVAILABLE_IN_2_36
+void g_subprocess_launcher_unsetenv (GSubprocessLauncher *self,
+ const gchar *variable);
+
+GLIB_AVAILABLE_IN_2_36
+const gchar * g_subprocess_launcher_getenv (GSubprocessLauncher *self,
+ const gchar *variable);
+
+GLIB_AVAILABLE_IN_2_36
+void g_subprocess_launcher_set_cwd (GSubprocessLauncher *self,
+ const gchar *cwd);
+GLIB_AVAILABLE_IN_2_36
+void g_subprocess_launcher_set_flags (GSubprocessLauncher *self,
+ GSubprocessFlags flags);
+
+/* Extended I/O control, only available on UNIX */
+#ifdef G_OS_UNIX
+GLIB_AVAILABLE_IN_2_36
+void g_subprocess_launcher_set_stdin_file_path (GSubprocessLauncher *self,
+ const gchar *path);
+GLIB_AVAILABLE_IN_2_36
+void g_subprocess_launcher_set_stdin_fd (GSubprocessLauncher *self,
+ gint fd);
+GLIB_AVAILABLE_IN_2_36
+void g_subprocess_launcher_set_stdout_file_path (GSubprocessLauncher *self,
+ const gchar *path);
+GLIB_AVAILABLE_IN_2_36
+void g_subprocess_launcher_set_stdout_fd (GSubprocessLauncher *self,
+ gint fd);
+GLIB_AVAILABLE_IN_2_36
+void g_subprocess_launcher_set_stderr_file_path (GSubprocessLauncher *self,
+ const gchar *path);
+GLIB_AVAILABLE_IN_2_36
+void g_subprocess_launcher_set_stderr_fd (GSubprocessLauncher *self,
+ gint fd);
+
+/* Child setup, only available on UNIX */
+GLIB_AVAILABLE_IN_2_36
+void g_subprocess_launcher_set_child_setup (GSubprocessLauncher *self,
+ GSpawnChildSetupFunc child_setup,
+ gpointer user_data,
+ GDestroyNotify destroy_notify);
+#endif
+
+G_END_DECLS
+
+#endif /* __G_SUBPROCESS_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]