subprocess WIP

This commit is contained in:
Ryan Lortie
2013-01-18 13:01:11 -05:00
parent 3388d9618b
commit d8913abf3b
11 changed files with 831 additions and 608 deletions

View File

@@ -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\

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -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.
*/
#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)
{
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;
}
else
#endif
if (self->context->stdin_disposition == G_SUBPROCESS_STREAM_DISPOSITION_NULL)
; /* nothing */
else if (self->context->stdin_disposition == G_SUBPROCESS_STREAM_DISPOSITION_INHERIT)
if (self->flags & G_SUBPROCESS_FLAGS_STDIN_INHERIT)
spawn_flags |= G_SPAWN_CHILD_INHERITS_STDIN;
else if (self->context->stdin_disposition == G_SUBPROCESS_STREAM_DISPOSITION_PIPE)
else if (self->flags & G_SUBPROCESS_FLAGS_STDIN_PIPE)
pipe_ptrs[0] = &pipe_fds[0];
else
g_assert_not_reached ();
#ifdef G_OS_UNIX
else if (self->launcher)
{
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;
}
}
#endif
/* Next, stdout. */
#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)
{
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;
}
else
#endif
if (self->context->stdout_disposition == G_SUBPROCESS_STREAM_DISPOSITION_NULL)
if (self->flags & G_SUBPROCESS_FLAGS_STDOUT_SILENCE)
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)
else if (self->flags & G_SUBPROCESS_FLAGS_STDOUT_PIPE)
pipe_ptrs[1] = &pipe_fds[1];
else
g_assert_not_reached ();
#ifdef G_OS_UNIX
else if (self->launcher)
{
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;
}
}
#endif
/* Finally, stderr. */
#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)
{
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;
}
else
#endif
if (self->context->stderr_disposition == G_SUBPROCESS_STREAM_DISPOSITION_NULL)
if (self->flags & G_SUBPROCESS_FLAGS_STDERR_SILENCE)
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)
else if (self->flags & G_SUBPROCESS_FLAGS_STDERR_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 ();
#ifdef G_OS_UNIX
if (self->launcher)
{
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;
}
}
#endif
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, using the parameters specified by
* GSubprocessContext.
* Create a new process with the given flags and varargs argument list.
*
* Returns: (transfer full): A newly created %GSubprocess, or %NULL on error (and @error will be set)
* 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
*/
GLIB_AVAILABLE_IN_2_36
GSubprocess *
g_subprocess_new (GSubprocessContext *context,
GError **error)
g_subprocess_new (GSubprocessFlags flags,
GError **error,
const gchar *argv0,
...)
{
return g_initable_new (G_TYPE_SUBPROCESS,
NULL, error,
"context", context,
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.
*
* The argument list is expected to be %NULL-terminated.
*
* Returns: A newly created #GSubprocess, or %NULL on error (and @error
* will be set)
*
* Since: 2.36
* Rename to: g_subprocess_new
*/
GSubprocess *
g_subprocess_newv (const gchar * const *argv,
GSubprocessFlags flags,
GError **error)
{
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;

View File

@@ -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);
/** High level helpers **/
gboolean g_subprocess_get_successful (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;
gboolean g_subprocess_get_if_exited (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_exit_status (GSubprocess *self);
GLIB_AVAILABLE_IN_2_36
gboolean g_subprocess_get_if_signaled (GSubprocess *self);
GLIB_AVAILABLE_IN_2_36
gint g_subprocess_get_term_signal (GSubprocess *self);
G_END_DECLS

View File

@@ -1,307 +0,0 @@
/* 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 Context
* @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
*/
#include "config.h"
#include "gsubprocesscontext-private.h"
#include "gsubprocess.h"
#include "gasyncresult.h"
#include "glibintl.h"
#include "glib-private.h"
#include <string.h>
typedef GObjectClass GSubprocessContextClass;
G_DEFINE_TYPE (GSubprocessContext, g_subprocess_context, G_TYPE_OBJECT);
enum
{
PROP_0,
PROP_ARGV,
N_PROPS
};
static GParamSpec *g_subprocess_context_pspecs[N_PROPS];
GSubprocessContext *
g_subprocess_context_new (gchar **argv)
{
return g_object_new (G_TYPE_SUBPROCESS_CONTEXT,
"argv", argv,
NULL);
}
static void
g_subprocess_context_init (GSubprocessContext *self)
{
self->argv = g_ptr_array_new_with_free_func (g_free);
self->stdin_fd = -1;
self->stdout_fd = -1;
self->stderr_fd = -1;
}
static void
g_subprocess_context_finalize (GObject *object)
{
GSubprocessContext *self = G_SUBPROCESS_CONTEXT (object);
g_ptr_array_unref (self->argv);
g_strfreev (self->envp);
g_free (self->cwd);
g_free (self->stdin_path);
g_free (self->stdout_path);
g_free (self->stderr_path);
if (G_OBJECT_CLASS (g_subprocess_context_parent_class)->finalize != NULL)
G_OBJECT_CLASS (g_subprocess_context_parent_class)->finalize (object);
}
static void
g_subprocess_context_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GSubprocessContext *self = G_SUBPROCESS_CONTEXT (object);
switch (prop_id)
{
case PROP_ARGV:
g_subprocess_context_set_args (self, (char**)g_value_get_boxed (value));
break;
default:
g_assert_not_reached ();
}
}
static void
g_subprocess_context_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GSubprocessContext *self = G_SUBPROCESS_CONTEXT (object);
switch (prop_id)
{
case PROP_ARGV:
g_value_set_boxed (value, self->argv->pdata);
break;
default:
g_assert_not_reached ();
}
}
static void
g_subprocess_context_class_init (GSubprocessContextClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
gobject_class->finalize = g_subprocess_context_finalize;
gobject_class->get_property = g_subprocess_context_get_property;
gobject_class->set_property = g_subprocess_context_set_property;
/**
* GSubprocessContext:argv:
*
* Array of arguments passed to child process; must have at least
* one element. The first element has special handling - if it is
* an not absolute path ( as determined by g_path_is_absolute() ),
* then the system search path will be used. See
* %G_SPAWN_SEARCH_PATH.
*
* Note that in order to use the Unix-specific argv0 functionality,
* you must use the setter function
* g_subprocess_context_set_args_and_argv0(). For more information
* about this, see %G_SPAWN_FILE_AND_ARGV_ZERO.
*
* Since: 2.36
*/
g_subprocess_context_pspecs[PROP_ARGV] = g_param_spec_boxed ("argv", P_("Arguments"), P_("Arguments for child process"), G_TYPE_STRV,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, N_PROPS, g_subprocess_context_pspecs);
}
/* Only exported on Unix */
#ifndef G_OS_UNIX
static
#endif
void
g_subprocess_context_set_args_and_argv0 (GSubprocessContext *self,
const gchar *argv0,
gchar **args)
{
gchar **iter;
g_ptr_array_set_size (self->argv, 0);
if (argv0)
g_ptr_array_add (self->argv, g_strdup (argv0));
for (iter = args; *iter; iter++)
g_ptr_array_add (self->argv, g_strdup (*iter));
g_ptr_array_add (self->argv, NULL);
}
void
g_subprocess_context_set_args (GSubprocessContext *self,
gchar **args)
{
g_subprocess_context_set_args_and_argv0 (self, NULL, args);
}
/* Environment */
void
g_subprocess_context_set_environment (GSubprocessContext *self,
gchar **environ)
{
g_strfreev (self->envp);
self->envp = g_strdupv (environ);
}
void
g_subprocess_context_set_cwd (GSubprocessContext *self,
const gchar *cwd)
{
g_free (self->cwd);
self->cwd = g_strdup (cwd);
}
void
g_subprocess_context_set_keep_descriptors (GSubprocessContext *self,
gboolean keep_descriptors)
{
self->keep_descriptors = keep_descriptors ? 1 : 0;
}
void
g_subprocess_context_set_search_path (GSubprocessContext *self,
gboolean search_path,
gboolean search_path_from_envp)
{
self->search_path = search_path ? 1 : 0;
self->search_path_from_envp = search_path_from_envp ? 1 : 0;
}
void
g_subprocess_context_set_stdin_disposition (GSubprocessContext *self,
GSubprocessStreamDisposition disposition)
{
g_return_if_fail (disposition != G_SUBPROCESS_STREAM_DISPOSITION_STDERR_MERGE);
self->stdin_disposition = disposition;
}
void
g_subprocess_context_set_stdout_disposition (GSubprocessContext *self,
GSubprocessStreamDisposition disposition)
{
g_return_if_fail (disposition != G_SUBPROCESS_STREAM_DISPOSITION_STDERR_MERGE);
self->stdout_disposition = disposition;
}
void
g_subprocess_context_set_stderr_disposition (GSubprocessContext *self,
GSubprocessStreamDisposition disposition)
{
self->stderr_disposition = disposition;
}
#ifdef G_OS_UNIX
void
g_subprocess_context_set_stdin_file_path (GSubprocessContext *self,
const gchar *path)
{
self->stdin_disposition = G_SUBPROCESS_STREAM_DISPOSITION_NULL;
g_free (self->stdin_path);
self->stdin_path = g_strdup (path);
}
void
g_subprocess_context_set_stdin_fd (GSubprocessContext *self,
gint fd)
{
self->stdin_disposition = G_SUBPROCESS_STREAM_DISPOSITION_NULL;
self->stdin_fd = fd;
}
void
g_subprocess_context_set_stdout_file_path (GSubprocessContext *self,
const gchar *path)
{
self->stdout_disposition = G_SUBPROCESS_STREAM_DISPOSITION_NULL;
g_free (self->stdout_path);
self->stdout_path = g_strdup (path);
}
void
g_subprocess_context_set_stdout_fd (GSubprocessContext *self,
gint fd)
{
self->stdout_disposition = G_SUBPROCESS_STREAM_DISPOSITION_NULL;
self->stdout_fd = fd;
}
void
g_subprocess_context_set_stderr_file_path (GSubprocessContext *self,
const gchar *path)
{
self->stderr_disposition = G_SUBPROCESS_STREAM_DISPOSITION_NULL;
g_free (self->stderr_path);
self->stderr_path = g_strdup (path);
}
void
g_subprocess_context_set_stderr_fd (GSubprocessContext *self,
gint fd)
{
self->stderr_disposition = G_SUBPROCESS_STREAM_DISPOSITION_NULL;
self->stderr_fd = fd;
}
#endif
#ifdef G_OS_UNIX
void
g_subprocess_context_set_child_setup (GSubprocessContext *self,
GSpawnChildSetupFunc child_setup,
gpointer user_data)
{
self->child_setup_func = child_setup;
self->child_setup_data = user_data;
}
#endif

View File

@@ -1,118 +0,0 @@
/* 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_CONTEXT_H__
#define __G_SUBPROCESS_CONTEXT_H__
#include <gio/giotypes.h>
G_BEGIN_DECLS
#define G_TYPE_SUBPROCESS_CONTEXT (g_subprocess_context_get_type ())
#define G_SUBPROCESS_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_SUBPROCESS_CONTEXT, GSubprocessContext))
#define G_IS_SUBPROCESS_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_SUBPROCESS_CONTEXT))
GLIB_AVAILABLE_IN_2_36
GType g_subprocess_context_get_type (void) G_GNUC_CONST;
GLIB_AVAILABLE_IN_2_36
GSubprocessContext * g_subprocess_context_new (gchar **argv);
/* Argument control */
GLIB_AVAILABLE_IN_2_36
void g_subprocess_context_set_args (GSubprocessContext *self,
gchar **args);
#ifdef G_OS_UNIX
GLIB_AVAILABLE_IN_2_36
void g_subprocess_context_set_args_and_argv0 (GSubprocessContext *self,
const gchar *argv0,
gchar **args);
#endif
/* Environment */
GLIB_AVAILABLE_IN_2_36
void g_subprocess_context_set_environment (GSubprocessContext *self,
gchar **environ);
GLIB_AVAILABLE_IN_2_36
void g_subprocess_context_set_cwd (GSubprocessContext *self,
const gchar *cwd);
GLIB_AVAILABLE_IN_2_36
void g_subprocess_context_set_keep_descriptors (GSubprocessContext *self,
gboolean keep_descriptors);
GLIB_AVAILABLE_IN_2_36
void g_subprocess_context_set_search_path (GSubprocessContext *self,
gboolean search_path,
gboolean search_path_from_envp);
/* Basic I/O control */
GLIB_AVAILABLE_IN_2_36
void g_subprocess_context_set_stdin_disposition (GSubprocessContext *self,
GSubprocessStreamDisposition disposition);
GLIB_AVAILABLE_IN_2_36
void g_subprocess_context_set_stdout_disposition (GSubprocessContext *self,
GSubprocessStreamDisposition disposition);
GLIB_AVAILABLE_IN_2_36
void g_subprocess_context_set_stderr_disposition (GSubprocessContext *self,
GSubprocessStreamDisposition disposition);
/* Extended I/O control, only available on UNIX */
#ifdef G_OS_UNIX
GLIB_AVAILABLE_IN_2_36
void g_subprocess_context_set_stdin_file_path (GSubprocessContext *self,
const gchar *path);
GLIB_AVAILABLE_IN_2_36
void g_subprocess_context_set_stdin_fd (GSubprocessContext *self,
gint fd);
GLIB_AVAILABLE_IN_2_36
void g_subprocess_context_set_stdout_file_path (GSubprocessContext *self,
const gchar *path);
GLIB_AVAILABLE_IN_2_36
void g_subprocess_context_set_stdout_fd (GSubprocessContext *self,
gint fd);
GLIB_AVAILABLE_IN_2_36
void g_subprocess_context_set_stderr_file_path (GSubprocessContext *self,
const gchar *path);
GLIB_AVAILABLE_IN_2_36
void g_subprocess_context_set_stderr_fd (GSubprocessContext *self,
gint fd);
#endif
/* Child setup, only available on UNIX */
#ifdef G_OS_UNIX
GLIB_AVAILABLE_IN_2_36
void g_subprocess_context_set_child_setup (GSubprocessContext *self,
GSpawnChildSetupFunc child_setup,
gpointer user_data);
#endif
G_END_DECLS
#endif /* __G_SUBPROCESS_H__ */

View File

@@ -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

536
gio/gsubprocesslauncher.c Normal file
View File

@@ -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

102
gio/gsubprocesslauncher.h Normal file
View File

@@ -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__ */