[gnome-terminal] client: FD passing
- From: Christian Persch <chpe src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-terminal] client: FD passing
- Date: Thu, 3 May 2012 19:05:11 +0000 (UTC)
commit f5fad240d85e8044055a50482452f9b4a53dc237
Author: Christian Persch <chpe gnome org>
Date: Tue Mar 20 21:32:52 2012 +0100
client: FD passing
src/client.c | 138 +++++++++++++++++++++++++++++++++++++++++++-
src/org.gnome.Terminal.xml | 1 +
src/terminal-controller.c | 8 ++-
src/terminal.c | 1 +
4 files changed, 144 insertions(+), 4 deletions(-)
---
diff --git a/src/client.c b/src/client.c
index 932f8a1..6fb7a90 100644
--- a/src/client.c
+++ b/src/client.c
@@ -34,6 +34,7 @@
#include <glib.h>
#include <glib/gprintf.h>
#include <gio/gio.h>
+#include <gio/gunixfdlist.h>
#include <gtk/gtk.h>
@@ -179,6 +180,10 @@ typedef struct
char *title;
double zoom;
+ /* Exec options */
+ GUnixFDList *fd_list;
+ GArray *fd_array;
+
/* Processing options */
gboolean wait;
@@ -242,6 +247,72 @@ option_bus_name_cb (const gchar *option_name,
return TRUE;
}
+typedef struct {
+ int index;
+ int fd;
+} PassFdElement;
+
+static gboolean
+option_fd_cb (const gchar *option_name,
+ const gchar *value,
+ gpointer user_data,
+ GError **error)
+{
+ OptionData *data = user_data;
+ int fd = -1;
+ PassFdElement e;
+
+ if (strcmp (option_name, "--fd") == 0) {
+ char *end = NULL;
+ errno = 0;
+ fd = g_ascii_strtoll (value, &end, 10);
+ if (errno != 0 || end == value) {
+ g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+ "Invalid argument \"%s\" to --fd option", value);
+ return FALSE;
+ }
+
+ } else if (strcmp (option_name, "--stdin") == 0) {
+ fd = STDIN_FILENO;
+ } else if (strcmp (option_name, "--stdout") == 0) {
+ fd = STDOUT_FILENO;
+ } else if (strcmp (option_name, "--stderr") == 0) {
+ fd = STDERR_FILENO;
+ } else {
+ g_assert_not_reached ();
+ }
+
+ if (data->fd_list == NULL) {
+ data->fd_list = g_unix_fd_list_new ();
+ data->fd_array = g_array_new (FALSE, FALSE, sizeof (PassFdElement));
+ } else {
+ guint i, n;
+ n = data->fd_array->len;
+ for (i = 0; i < n; i++) {
+ e = g_array_index (data->fd_array, PassFdElement, i);
+ if (e.fd == fd) {
+ g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+ "Cannot pass FD %d twice", fd);
+ return FALSE;
+ }
+ }
+ }
+
+ e.fd = fd;
+ e.index = g_unix_fd_list_append (data->fd_list, fd, error);
+ if (e.index == -1)
+ return FALSE;
+
+ g_array_append_val (data->fd_array, e);
+
+ if (fd == STDOUT_FILENO || fd == STDERR_FILENO)
+ quiet = TRUE;
+ if (fd == STDIN_FILENO)
+ data->wait = TRUE;
+
+ return TRUE;
+}
+
static GOptionContext *
get_goption_context (OptionData *data)
{
@@ -282,6 +353,18 @@ get_goption_context (OptionData *data)
{ NULL, 0, 0, 0, NULL, NULL, NULL }
};
+ const GOptionEntry exec_goptions[] = {
+ { "stdin", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, option_fd_cb,
+ N_("Forward stdin"), NULL },
+ { "stdout", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, option_fd_cb,
+ N_("Forward stdout"), NULL },
+ { "stderr", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, option_fd_cb,
+ N_("Forward stderr"), NULL },
+ { "fd", 0, 0, G_OPTION_ARG_CALLBACK, option_fd_cb,
+ N_("Forward file descriptor"), N_("FD") },
+ { NULL, 0, 0, 0, NULL, NULL, NULL }
+ };
+
const GOptionEntry processing_goptions[] = {
{ "wait", 0, 0, G_OPTION_ARG_NONE, &data->wait,
N_("Wait until the child exits"), NULL },
@@ -329,6 +412,15 @@ get_goption_context (OptionData *data)
g_option_group_add_entries (group, terminal_goptions);
g_option_context_add_group (context, group);
+ group = g_option_group_new ("exec-goptions",
+ N_("Exec options:"),
+ N_("Show exec options"),
+ data,
+ NULL);
+ g_option_group_set_translation_domain (group, GETTEXT_PACKAGE);
+ g_option_group_add_entries (group, exec_goptions);
+ g_option_context_add_group (context, group);
+
group = g_option_group_new ("processing-goptions",
N_("Processing options:"),
N_("Show processing options"),
@@ -357,6 +449,13 @@ option_data_free (OptionData *data)
g_free (data->working_directory);
g_free (data->profile);
g_free (data->title);
+
+ if (data->fd_list)
+ g_object_unref (data->fd_list);
+ if (data->fd_array)
+ g_array_free (data->fd_array, TRUE);
+
+ g_free (data);
}
static OptionData *
@@ -437,7 +536,8 @@ build_create_options_variant (OptionData *data)
* Returns: a floating #GVariant
*/
static GVariant *
-build_exec_options_variant (OptionData *data)
+build_exec_options_variant (OptionData *data,
+ GUnixFDList **fd_list)
{
GVariantBuilder builder;
@@ -446,6 +546,31 @@ build_exec_options_variant (OptionData *data)
terminal_client_append_exec_options (&builder,
data->working_directory);
+ if (data->fd_array != NULL) {
+ int i, n_fds;
+
+ g_variant_builder_open (&builder, G_VARIANT_TYPE ("{sv}"));
+ g_variant_builder_add (&builder, "s", "fd-set");
+
+ g_variant_builder_open (&builder, G_VARIANT_TYPE ("v"));
+ g_variant_builder_open (&builder, G_VARIANT_TYPE ("a(ih)"));
+ n_fds = (int) data->fd_array->len;
+ for (i = 0; i < n_fds; i++) {
+ PassFdElement e = g_array_index (data->fd_array, PassFdElement, i);
+
+ g_variant_builder_add (&builder, "(ih)", e.fd, e.index);
+ }
+ g_variant_builder_close (&builder); /* a(ih) */
+ g_variant_builder_close (&builder); /* v */
+
+ g_variant_builder_close (&builder); /* {sv} */
+
+ *fd_list = data->fd_list;
+ data->fd_list = NULL;
+ } else {
+ *fd_list = NULL;
+ }
+
return g_variant_builder_end (&builder);
}
@@ -478,6 +603,8 @@ handle_open (int *argc,
TerminalReceiver *receiver;
GError *error = NULL;
char *object_path;
+ GVariant *arguments;
+ GUnixFDList *fd_list;
modify_argv0_for_command (argc, argv, "open");
@@ -537,17 +664,22 @@ handle_open (int *argc,
g_free (object_path);
+ arguments = build_exec_options_variant (data, &fd_list);
if (!terminal_receiver_call_exec_sync (receiver,
- build_exec_options_variant (data),
+ arguments,
g_variant_new_bytestring_array ((const char * const *) data->exec_argv, data->exec_argc),
+ fd_list,
+ NULL, /* outfdlist */
NULL /* cancellable */,
&error)) {
- g_printerr ("Error: %s\n", error->message);
+ _printerr ("Error: %s\n", error->message);
g_error_free (error);
+ g_clear_object (fd_list);
g_object_unref (receiver);
option_data_free (data);
return FALSE;
}
+ g_clear_object (fd_list);
if (data->wait) {
WaitData wait_data;
diff --git a/src/org.gnome.Terminal.xml b/src/org.gnome.Terminal.xml
index 06fe6ab..a6ada0e 100644
--- a/src/org.gnome.Terminal.xml
+++ b/src/org.gnome.Terminal.xml
@@ -29,6 +29,7 @@
<interface name="org.gnome.Terminal.Terminal0">
<annotation name="org.gtk.GDBus.C.Name" value="Receiver" />
<method name="Exec">
+ <annotation name="org.gtk.GDBus.C.UnixFD" value="true" />
<arg type="a{sv}" name="options" direction="in" />
<arg type="aay" name="arguments" direction="in">
<annotation name="org.gtk.GDBus.C.ForceGVariant" value="true" />
diff --git a/src/terminal-controller.c b/src/terminal-controller.c
index db74871..b5b1635 100644
--- a/src/terminal-controller.c
+++ b/src/terminal-controller.c
@@ -82,6 +82,7 @@ terminal_controller_set_screen (TerminalController *controller,
static gboolean
terminal_controller_exec (TerminalReceiver *receiver,
GDBusMethodInvocation *invocation,
+ GUnixFDList *fd_list,
GVariant *options,
GVariant *arguments)
{
@@ -90,6 +91,7 @@ terminal_controller_exec (TerminalReceiver *receiver,
const char *working_directory;
char **exec_argv, **envv;
gsize exec_argc;
+ GVariantIter *fd_iter;
GError *error;
if (priv->screen == NULL) {
@@ -104,6 +106,8 @@ terminal_controller_exec (TerminalReceiver *receiver,
working_directory = NULL;
if (!g_variant_lookup (options, "environ", "^a&ay", &envv))
envv = NULL;
+ if (!g_variant_lookup (options, "fd-set", "a(ih)", &fd_iter))
+ fd_iter = NULL;
if (working_directory != NULL)
_terminal_debug_print (TERMINAL_DEBUG_FACTORY,
@@ -119,11 +123,13 @@ terminal_controller_exec (TerminalReceiver *receiver,
&error)) {
g_dbus_method_invocation_take_error (invocation, error);
} else {
- terminal_receiver_complete_exec (receiver, invocation);
+ terminal_receiver_complete_exec (receiver, invocation, NULL /* outfdlist */);
}
g_free (exec_argv);
g_free (envv);
+ if (fd_iter)
+ g_variant_iter_free (fd_iter);
out:
diff --git a/src/terminal.c b/src/terminal.c
index 483de58..41e6003 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -213,6 +213,7 @@ handle_options (TerminalFactory *factory,
if (!terminal_receiver_call_exec_sync (receiver,
g_variant_builder_end (&builder),
g_variant_new_bytestring_array ((const char * const *) argv, argc),
+ NULL /* infdlist */, NULL /* outfdlist */,
NULL /* cancellable */,
&err)) {
g_printerr ("Error: %s\n", err->message);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]