From: David Zeuthen Date: Tue, 6 Jul 2010 20:57:28 +0000 (-0400) Subject: GDBus: Handle autolaunching on UNIX/Freedesktop OSes X-Git-Tag: 2.25.11~62 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=aab6d9ed1c54f215838da7939a97e33d46d94036;p=platform%2Fupstream%2Fglib.git GDBus: Handle autolaunching on UNIX/Freedesktop OSes Also add a 'address' G_DBUS_DEBUG option that will print out useful debug information such as GDBus-debug:Address: In g_dbus_address_get_for_bus_sync() for bus type `session' GDBus-debug:Address: env var DBUS_SESSION_BUS_ADDRESS is not set GDBus-debug:Address: env var DBUS_SYSTEM_BUS_ADDRESS is not set GDBus-debug:Address: env var DBUS_STARTER_BUS_TYPE is not set GDBus-debug:Address: Running `dbus-launch --autolaunch=05e508961149264c9b750a4c494aa6f7 --binary-syntax --close-stderr' to get bus address (possibly autolaunching) GDBus-debug:Address: dbus-launch output: 0000: 75 6e 69 78 3a 61 62 73 74 72 61 63 74 3d 2f 74 unix:abstract=/t 0010: 6d 70 2f 64 62 75 73 2d 77 42 41 6f 4b 59 49 52 mp/dbus-wBAoKYIR 0020: 7a 75 2c 67 75 69 64 3d 30 34 30 64 31 33 66 33 zu,guid=040d13f3 0030: 30 61 30 62 35 32 63 32 30 66 36 32 63 34 31 63 0a0b52c20f62c41c 0040: 30 30 30 30 35 30 38 64 00 d2 38 00 00 01 00 40 0000508d..8....@ 0050: 05 00 00 00 00 ..... GDBus-debug:Address: dbus-launch stderr output: 14542: Autolaunch enabled (using X11). 14542: --exit-with-session automatically enabled 14542: Connected to X11 display ':0.0' 14542: === Parent dbus-launch continues 14542: Waiting for babysitter's intermediate parent 14542: Reading address from bus 14542: Reading PID from daemon 14542: Saving x11 address 14542: Created window 88080385 14542: session file: /root/.dbus/session-bus/05e508961149264c9b750a4c494aa6f7-0 14542: dbus-launch exiting GDBus-debug:Address: Returning address `unix:abstract=/tmp/dbus-wBAoKYIRzu,guid=040d13f30a0b52c20f62c41c0000508d' for bus type `session' and GDBus-debug:Address: In g_dbus_address_get_for_bus_sync() for bus type `session' GDBus-debug:Address: env var DBUS_SESSION_BUS_ADDRESS is not set GDBus-debug:Address: env var DBUS_SYSTEM_BUS_ADDRESS is not set GDBus-debug:Address: env var DBUS_STARTER_BUS_TYPE is not set GDBus-debug:Address: Running `dbus-launch --autolaunch=05e508961149264c9b750a4c494aa6f7 --binary-syntax --close-stderr' to get bus address (possibly autolaunching) GDBus-debug:Address: dbus-launch output: 0000: 75 6e 69 78 3a 61 62 73 74 72 61 63 74 3d 2f 74 unix:abstract=/t 0010: 6d 70 2f 64 62 75 73 2d 77 42 41 6f 4b 59 49 52 mp/dbus-wBAoKYIR 0020: 7a 75 2c 67 75 69 64 3d 30 34 30 64 31 33 66 33 zu,guid=040d13f3 0030: 30 61 30 62 35 32 63 32 30 66 36 32 63 34 31 63 0a0b52c20f62c41c 0040: 30 30 30 30 35 30 38 64 00 d2 38 00 00 01 00 40 0000508d..8....@ 0050: 05 00 00 00 00 ..... GDBus-debug:Address: dbus-launch stderr output: 14549: Autolaunch enabled (using X11). 14549: --exit-with-session automatically enabled 14549: Connected to X11 display ':0.0' 14549: dbus-daemon is already running. Returning existing parameters. 14549: dbus-launch exiting GDBus-debug:Address: Returning address `unix:abstract=/tmp/dbus-wBAoKYIRzu,guid=040d13f30a0b52c20f62c41c0000508d' for bus type `session' Note that things work exactly like libdbus, e.g. from the dbus-launch(1) man page: Whenever an autolaunch occurs, the application that had to start a new bus will be in its own little world; it can effectively end up starting a whole new session if it tries to use a lot of bus services. This can be suboptimal or even totally broken, depending on the app and what it tries to do. [...] You can always avoid autolaunch by manually setting DBUS_SESSION_BUS_ADDRESS. Autolaunch happens because the default address if none is set is "autolaunch:", so if any other address is set there will be no autolaunch. You can however include autolaunch in an explicit session bus address as a fallback, for example DBUS_SESSION_BUS_ADDRESS="something:,autolaunch:" - in that case if the first address doesn't work, processes will autolaunch. (The bus address variable contains a comma-separated list of addresses to try.) Signed-off-by: David Zeuthen --- diff --git a/docs/reference/gio/overview.xml b/docs/reference/gio/overview.xml index 37c469c..5f7be19 100644 --- a/docs/reference/gio/overview.xml +++ b/docs/reference/gio/overview.xml @@ -367,6 +367,10 @@ authentication Show information about connection authentication + + address + Show information about D-Bus address lookups and autolaunching + The special value all can be used to turn on all debug options. diff --git a/gio/gdbusaddress.c b/gio/gdbusaddress.c index 21c5203..17598b3 100644 --- a/gio/gdbusaddress.c +++ b/gio/gdbusaddress.c @@ -55,6 +55,8 @@ * is explained in detail in the D-Bus specification. */ +static gchar *get_session_address_platform_specific (GError **error); + /* ---------------------------------------------------------------------------------------------------- */ /** @@ -386,6 +388,8 @@ g_dbus_is_supported_address (const gchar *string, supported = is_valid_tcp (a[n], key_value_pairs, error); else if (g_strcmp0 (transport_name, "nonce-tcp") == 0) supported = is_valid_nonce_tcp (a[n], key_value_pairs, error); + else if (g_strcmp0 (a[n], "autolaunch:") == 0) + supported = TRUE; g_free (transport_name); g_hash_table_unref (key_value_pairs); @@ -488,6 +492,12 @@ out: /* ---------------------------------------------------------------------------------------------------- */ +static GIOStream * +g_dbus_address_try_connect_one (const gchar *address_entry, + gchar **out_guid, + GCancellable *cancellable, + GError **error); + /* TODO: Declare an extension point called GDBusTransport (or similar) * and move code below to extensions implementing said extension * point. That way we can implement a D-Bus transport over X11 without @@ -596,6 +606,21 @@ g_dbus_address_connect (const gchar *address_entry, /* TODO: deal with family */ connectable = g_network_address_new (host, port); } + else if (g_strcmp0 (address_entry, "autolaunch:") == 0) + { + gchar *autolaunch_address; + autolaunch_address = get_session_address_platform_specific (error); + if (autolaunch_address != NULL) + { + ret = g_dbus_address_try_connect_one (autolaunch_address, NULL, cancellable, error); + g_free (autolaunch_address); + goto out; + } + else + { + g_prefix_error (error, _("Error auto-launching: ")); + } + } else { g_set_error (error, @@ -931,11 +956,168 @@ g_dbus_address_get_stream_sync (const gchar *address, /* ---------------------------------------------------------------------------------------------------- */ +#ifdef G_OS_UNIX +static gchar * +get_session_address_dbus_launch (GError **error) +{ + gchar *ret; + gchar *machine_id; + gchar *command_line; + gchar *launch_stdout; + gchar *launch_stderr; + gint exit_status; + gchar *old_dbus_verbose; + gboolean restore_dbus_verbose; + + ret = NULL; + machine_id = NULL; + command_line = NULL; + launch_stdout = NULL; + launch_stderr = NULL; + restore_dbus_verbose = FALSE; + old_dbus_verbose = NULL; + + machine_id = _g_dbus_get_machine_id (error); + if (machine_id == NULL) + { + g_prefix_error (error, _("Cannot spawn a message bus without a machine-id: ")); + goto out; + } + + /* We're using private libdbus facilities here. When everything + * (X11, Mac OS X, Windows) is spec'ed out correctly (not even the + * X11 property is correctly documented right now) we should + * consider using the spec instead of dbus-launch. + * + * --autolaunch=MACHINEID + * This option implies that dbus-launch should scan for a previ‐ + * ously-started session and reuse the values found there. If no + * session is found, it will start a new session. The --exit-with- + * session option is implied if --autolaunch is given. This option + * is for the exclusive use of libdbus, you do not want to use it + * manually. It may change in the future. + */ + + /* TODO: maybe provide a variable for where to look for the dbus-launch binary? */ + command_line = g_strdup_printf ("dbus-launch --autolaunch=%s --binary-syntax --close-stderr", machine_id); + + if (G_UNLIKELY (_g_dbus_debug_address ())) + { + _g_dbus_debug_print_lock (); + g_print ("GDBus-debug:Address: Running `%s' to get bus address (possibly autolaunching)\n", command_line); + old_dbus_verbose = g_strdup (g_getenv ("DBUS_VERBOSE")); + restore_dbus_verbose = TRUE; + g_setenv ("DBUS_VERBOSE", "1", TRUE); + _g_dbus_debug_print_unlock (); + } + + if (!g_spawn_command_line_sync (command_line, + &launch_stdout, + &launch_stderr, + &exit_status, + error)) + { + g_prefix_error (error, _("Error spawning command line `%s': "), command_line); + goto out; + } + + if (!WIFEXITED (exit_status)) + { + gchar *escaped_stderr; + escaped_stderr = g_strescape (launch_stderr, ""); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + _("Abnormal program termination spawning command line `%s': %s"), + command_line, + escaped_stderr); + g_free (escaped_stderr); + goto out; + } + + if (WEXITSTATUS (exit_status) != 0) + { + gchar *escaped_stderr; + escaped_stderr = g_strescape (launch_stderr, ""); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + _("Command line `%s' exited with non-zero exit status %d: %s"), + command_line, + WEXITSTATUS (exit_status), + escaped_stderr); + g_free (escaped_stderr); + goto out; + } + + /* From the dbus-launch(1) man page: + * + * --binary-syntax Write to stdout a nul-terminated bus address, + * then the bus PID as a binary integer of size sizeof(pid_t), + * then the bus X window ID as a binary integer of size + * sizeof(long). Integers are in the machine's byte order, not + * network byte order or any other canonical byte order. + */ + ret = g_strdup (launch_stdout); + + out: + if (G_UNLIKELY (_g_dbus_debug_address ())) + { + gchar *s; + _g_dbus_debug_print_lock (); + g_print ("GDBus-debug:Address: dbus-launch output:"); + if (launch_stdout != NULL) + { + s = _g_dbus_hexdump (launch_stdout, strlen (launch_stdout) + 1 + sizeof (pid_t) + sizeof (long), 2); + g_print ("\n%s", s); + g_free (s); + } + else + { + g_print (" (none)\n"); + } + g_print ("GDBus-debug:Address: dbus-launch stderr output:"); + if (launch_stderr != NULL) + g_print ("\n%s", launch_stderr); + else + g_print (" (none)\n"); + _g_dbus_debug_print_unlock (); + } + + g_free (machine_id); + g_free (command_line); + g_free (launch_stdout); + g_free (launch_stderr); + if (G_UNLIKELY (restore_dbus_verbose)) + { + if (old_dbus_verbose != NULL) + g_setenv ("DBUS_VERBOSE", old_dbus_verbose, TRUE); + else + g_unsetenv ("DBUS_VERBOSE"); + } + g_free (old_dbus_verbose); + return ret; +} +#endif + +/* ---------------------------------------------------------------------------------------------------- */ + /* TODO: implement for UNIX, Win32 and OS X */ static gchar * -get_session_address_platform_specific (void) +get_session_address_platform_specific (GError **error) { - return NULL; + gchar *ret; +#ifdef G_OS_UNIX + /* need to handle OS X in a different way since `dbus-launch --autolaunch' probably won't work there */ + ret = get_session_address_dbus_launch (error); +#else + ret = NULL; + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + _("Cannot determine session bus address (not implemented for this OS)")); +#endif + return ret; } /* ---------------------------------------------------------------------------------------------------- */ @@ -961,10 +1143,39 @@ g_dbus_address_get_for_bus_sync (GBusType bus_type, { gchar *ret; const gchar *starter_bus; + GError *local_error; g_return_val_if_fail (error == NULL || *error == NULL, NULL); ret = NULL; + local_error = NULL; + + if (G_UNLIKELY (_g_dbus_debug_address ())) + { + guint n; + _g_dbus_debug_print_lock (); + g_print ("GDBus-debug:Address: In g_dbus_address_get_for_bus_sync() for bus type `%s'\n", + _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type)); + for (n = 0; n < 3; n++) + { + const gchar *k; + const gchar *v; + switch (n) + { + case 0: k = "DBUS_SESSION_BUS_ADDRESS"; break; + case 1: k = "DBUS_SYSTEM_BUS_ADDRESS"; break; + case 2: k = "DBUS_STARTER_BUS_TYPE"; break; + default: g_assert_not_reached (); + } + v = g_getenv (k); + g_print ("GDBus-debug:Address: env var %s", k); + if (v != NULL) + g_print ("=`%s'\n", v); + else + g_print (" is not set\n"); + } + _g_dbus_debug_print_unlock (); + } switch (bus_type) { @@ -980,14 +1191,7 @@ g_dbus_address_get_for_bus_sync (GBusType bus_type, ret = g_strdup (g_getenv ("DBUS_SESSION_BUS_ADDRESS")); if (ret == NULL) { - ret = get_session_address_platform_specific (); - if (ret == NULL) - { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - _("Cannot determine session bus address (TODO: run dbus-launch to find out)")); - } + ret = get_session_address_platform_specific (&local_error); } break; @@ -995,19 +1199,19 @@ g_dbus_address_get_for_bus_sync (GBusType bus_type, starter_bus = g_getenv ("DBUS_STARTER_BUS_TYPE"); if (g_strcmp0 (starter_bus, "session") == 0) { - ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION, cancellable, error); + ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION, cancellable, &local_error); goto out; } else if (g_strcmp0 (starter_bus, "system") == 0) { - ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SYSTEM, cancellable, error); + ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SYSTEM, cancellable, &local_error); goto out; } else { if (starter_bus != NULL) { - g_set_error (error, + g_set_error (&local_error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Cannot determine bus address from DBUS_STARTER_BUS_TYPE environment variable" @@ -1016,7 +1220,7 @@ g_dbus_address_get_for_bus_sync (GBusType bus_type, } else { - g_set_error_literal (error, + g_set_error_literal (&local_error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Cannot determine bus address because the DBUS_STARTER_BUS_TYPE environment " @@ -1026,7 +1230,7 @@ g_dbus_address_get_for_bus_sync (GBusType bus_type, break; default: - g_set_error (error, + g_set_error (&local_error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Unknown bus type %d"), @@ -1035,6 +1239,27 @@ g_dbus_address_get_for_bus_sync (GBusType bus_type, } out: + if (G_UNLIKELY (_g_dbus_debug_address ())) + { + _g_dbus_debug_print_lock (); + if (ret != NULL) + { + g_print ("GDBus-debug:Address: Returning address `%s' for bus type `%s'\n", + ret, + _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type)); + } + else + { + g_print ("GDBus-debug:Address: Cannot look-up address bus type `%s': %s\n", + _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type), + local_error->message); + } + _g_dbus_debug_print_unlock (); + } + + if (local_error != NULL) + g_propagate_error (error, local_error); + return ret; } diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c index 908dfea..e853281 100644 --- a/gio/gdbusconnection.c +++ b/gio/gdbusconnection.c @@ -5356,24 +5356,16 @@ handle_generic_get_machine_id_unlocked (GDBusConnection *connection, if (connection->priv->machine_id == NULL) { GError *error; + error = NULL; - /* TODO: use PACKAGE_LOCALSTATEDIR ? */ - if (!g_file_get_contents ("/var/lib/dbus/machine-id", - &connection->priv->machine_id, - NULL, - &error)) + connection->priv->machine_id = _g_dbus_get_machine_id (&error); + if (connection->priv->machine_id == NULL) { - reply = g_dbus_message_new_method_error (message, - "org.freedesktop.DBus.Error.Failed", - _("Unable to load /var/lib/dbus/machine-id: %s"), - error->message); + reply = g_dbus_message_new_method_error_literal (message, + "org.freedesktop.DBus.Error.Failed", + error->message); g_error_free (error); } - else - { - g_strstrip (connection->priv->machine_id); - /* TODO: validate value */ - } } if (reply == NULL) diff --git a/gio/gdbusmessage.c b/gio/gdbusmessage.c index 345fdc4..0523d78 100644 --- a/gio/gdbusmessage.c +++ b/gio/gdbusmessage.c @@ -2605,23 +2605,6 @@ g_dbus_message_to_gerror (GDBusMessage *message, /* ---------------------------------------------------------------------------------------------------- */ static gchar * -enum_to_string (GType enum_type, gint value) -{ - gchar *ret; - GEnumClass *klass; - GEnumValue *enum_value; - - klass = g_type_class_ref (enum_type); - enum_value = g_enum_get_value (klass, value); - if (enum_value != NULL) - ret = g_strdup (enum_value->value_nick); - else - ret = g_strdup_printf ("unknown (value %d)", value); - g_type_class_unref (klass); - return ret; -} - -static gchar * flags_to_string (GType flags_type, guint value) { GString *s; @@ -2720,7 +2703,7 @@ g_dbus_message_print (GDBusMessage *message, str = g_string_new (NULL); - s = enum_to_string (G_TYPE_DBUS_MESSAGE_TYPE, message->priv->type); + s = _g_dbus_enum_to_string (G_TYPE_DBUS_MESSAGE_TYPE, message->priv->type); g_string_append_printf (str, "%*sType: %s\n", indent, "", s); g_free (s); s = flags_to_string (G_TYPE_DBUS_MESSAGE_FLAGS, message->priv->flags); @@ -2743,7 +2726,7 @@ g_dbus_message_print (GDBusMessage *message, value = g_hash_table_lookup (message->priv->headers, l->data); g_assert (value != NULL); - s = enum_to_string (G_TYPE_DBUS_MESSAGE_HEADER_FIELD, key); + s = _g_dbus_enum_to_string (G_TYPE_DBUS_MESSAGE_HEADER_FIELD, key); value_str = g_variant_print (value, TRUE); g_string_append_printf (str, "%*s %s -> %s\n", indent, "", s, value_str); g_free (s); diff --git a/gio/gdbusprivate.c b/gio/gdbusprivate.c index 185877f..bcc031e 100644 --- a/gio/gdbusprivate.c +++ b/gio/gdbusprivate.c @@ -1099,6 +1099,7 @@ _g_dbus_worker_stop (GDBusWorker *worker) #define G_DBUS_DEBUG_SIGNAL (1<<4) #define G_DBUS_DEBUG_INCOMING (1<<5) #define G_DBUS_DEBUG_EMISSION (1<<6) +#define G_DBUS_DEBUG_ADDRESS (1<<7) #define G_DBUS_DEBUG_ALL 0xffffffff static gint _gdbus_debug_flags = 0; @@ -1151,6 +1152,13 @@ _g_dbus_debug_emission (void) return (_gdbus_debug_flags & G_DBUS_DEBUG_EMISSION) != 0; } +gboolean +_g_dbus_debug_address (void) +{ + _g_dbus_initialize (); + return (_gdbus_debug_flags & G_DBUS_DEBUG_ADDRESS) != 0; +} + G_LOCK_DEFINE_STATIC (print_lock); void @@ -1207,6 +1215,8 @@ _g_dbus_initialize (void) _gdbus_debug_flags |= G_DBUS_DEBUG_INCOMING; else if (g_strcmp0 (tokens[n], "emission") == 0) _gdbus_debug_flags |= G_DBUS_DEBUG_EMISSION; + else if (g_strcmp0 (tokens[n], "address") == 0) + _gdbus_debug_flags |= G_DBUS_DEBUG_ADDRESS; else if (g_strcmp0 (tokens[n], "all") == 0) _gdbus_debug_flags |= G_DBUS_DEBUG_ALL; } @@ -1313,5 +1323,47 @@ out: /* ---------------------------------------------------------------------------------------------------- */ +gchar * +_g_dbus_get_machine_id (GError **error) +{ + gchar *ret; + /* TODO: use PACKAGE_LOCALSTATEDIR ? */ + ret = NULL; + if (!g_file_get_contents ("/var/lib/dbus/machine-id", + &ret, + NULL, + error)) + { + g_prefix_error (error, _("Unable to load /var/lib/dbus/machine-id: ")); + } + else + { + /* TODO: validate value */ + g_strstrip (ret); + } + return ret; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +gchar * +_g_dbus_enum_to_string (GType enum_type, gint value) +{ + gchar *ret; + GEnumClass *klass; + GEnumValue *enum_value; + + klass = g_type_class_ref (enum_type); + enum_value = g_enum_get_value (klass, value); + if (enum_value != NULL) + ret = g_strdup (enum_value->value_nick); + else + ret = g_strdup_printf ("unknown (value %d)", value); + g_type_class_unref (klass); + return ret; +} + +/* ---------------------------------------------------------------------------------------------------- */ + #define __G_DBUS_PRIVATE_C__ #include "gioaliasdef.c" diff --git a/gio/gdbusprivate.h b/gio/gdbusprivate.h index 7207d2f..91a78c4 100644 --- a/gio/gdbusprivate.h +++ b/gio/gdbusprivate.h @@ -81,6 +81,8 @@ gboolean _g_dbus_debug_call (void); gboolean _g_dbus_debug_signal (void); gboolean _g_dbus_debug_incoming (void); gboolean _g_dbus_debug_emission (void); +gboolean _g_dbus_debug_address (void); + void _g_dbus_debug_print_lock (void); void _g_dbus_debug_print_unlock (void); @@ -99,6 +101,10 @@ gchar *_g_dbus_hexdump (const gchar *data, gsize len, guint indent); gchar *_g_dbus_win32_get_user_sid (void); #endif +gchar *_g_dbus_get_machine_id (GError **error); + +gchar *_g_dbus_enum_to_string (GType enum_type, gint value); + G_END_DECLS #endif /* __G_DBUS_PRIVATE_H__ */