DBus on OS X: reintroducing "classical" X11 (auto-)start as a fall-back
René J.V. Bertin <[email protected]>
| Newsgroups | gmane.comp.freedesktop.dbus |
|---|---|
| Message-ID | <2917932.zIAPxt7Q6U@patux> |
Hi, The current DBus implementation for OS X only supports (auto) starting through launchd, when the user is logged in a local, "Aqua" session. On the one hand that certainly caters to the large majority of use cases, but on the other hand DBus is used (mostly?) with applications that weren't written specifically for OS X using native APIs. It doesn't seem far-fetched to assume that users who install gnome/gtk applications or Qt's xcb platform plugin expect to be able to use those applications also on a remote X11 display (I do, and from feedback elsewhere I deduce that I'm not alone). That would require a functional DBus that works and is started just like it would be on a "non-Mac Unix system" (to quote a comment in dbus source code). After an exchange with Thiago Macieira (started because I was surprised to see Qt5 applications that don't even use DBus give an error when started on a remote X11 connection) I've started looking into modifying the code so that it would start a DBus daemon linked to the X11 connection. I'd need and appreciate some guidance: I've followed the idea that it would be best to let the OS X default launchd starting mechanism fail gracefully, and then attempt to do the X11 default start as a fallback. It turns out to be rather easy to check if we're running in a context where launchd would allow to start the DBus. The launchd plist instructs it to do this only in Aqua sessions (which makes sense I guess), and one can obtain the current session type from launchctl. That would allow to "punt and fall back" as commented in dbus-sysdeps-unix.c . With the attached patch (against 1.8.16), I get a failure with the error %> dbus-launch --csh-syntax Failed to start message bus: Unknown address type 'launchd' EOF in dbus-launch reading address from bus daemon Exit 1 It looks like I'm also going to need to modify dbus_server_listen (dbus-server.c) and/or bus_context_new (bus.c) so that other methods or addresses are tried if the launchd one fails. I haven't yet been able to follow where dbus_server_listen() and bus_context_new() get their list of options to try from. A config file, or something hard-coded? Is there a better approach to accomplish this than the one I'm following? I'd like this to be as transparent as possible, so that no changes outside of DBus are required, and a daemon is started when needed both in an "Aqua" session (current behaviour) and when logged in from a remote host and displaying over X11 on that host. Thanks, René _______________________________________________ dbus mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/dbus
patch-dbus-enable-nonlaunchd-start.diff
(text/x-patch, 6.5 KB)
diff --git a/dbus/dbus-server-unix.c b/dbus/dbus-server-unix.c
index d995240..fccb861 100644
--- a/dbus/dbus-server-unix.c
+++ b/dbus/dbus-server-unix.c
@@ -195,6 +195,14 @@ _dbus_server_listen_platform_specific (DBusAddressEntry *entry,
#ifdef DBUS_ENABLE_LAUNCHD
else if (strcmp (method, "launchd") == 0)
{
+ if (!_dbus_match_launchd_session_type("Aqua", error))
+ {
+ /* We don't handle this method when the session type is inappropriate;
+ * we return NULL with the error unset
+ */
+ _DBUS_ASSERT_ERROR_IS_CLEAR(error);
+ return DBUS_SERVER_LISTEN_NOT_HANDLED;
+ }
const char *launchd_env_var = dbus_address_entry_get_value (entry, "env");
if (launchd_env_var == NULL)
{
diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c
index 9e3f057..8e87b1e 100644
--- a/dbus/dbus-sysdeps-unix.c
+++ b/dbus/dbus-sysdeps-unix.c
@@ -3647,11 +3647,106 @@ _dbus_read_local_machine_uuid (DBusGUID *machine_id,
}
/**
- * quries launchd for a specific env var which holds the socket path.
+ * queries launchd for the current session type: this will be Aqua
+ * when we're called running under an "Aqua" session on the local screen,
+ * regardless of what kind of application (native, X11, commandline, ...)
+ * we are. It will be something else (typically Background) when we're
+ * called from a remote connection
+ * @param session_type DBusString that will contain the returned type
+ * @param error a DBusError to store the error in case of failure
+ * @return true on success, false on error
+ */
+dbus_bool_t
+_dbus_lookup_launchd_session_type (DBusString *session_type,
+ DBusError *error)
+{
+#ifdef DBUS_ENABLE_LAUNCHD
+ char *argv[3];
+ int i;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ if (_dbus_check_setuid ())
+ {
+ dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED,
+ "Using launchd is not supported when setuid");
+ return FALSE;
+ }
+
+ i = 0;
+ argv[i] = "launchctl";
+ ++i;
+ // from `man launchctl`:
+ // This prints the name of the launchd job manager which manages the current bootstrap.
+ // See LimitLoad-ToSessionType in launchd.plist(5) for more details.
+ argv[i] = "managername";
+ ++i;
+ argv[i] = NULL;
+ ++i;
+
+ _dbus_assert (i == _DBUS_N_ELEMENTS (argv));
+
+ if (!_read_subprocess_line_argv(argv[0], TRUE, argv, session_type, error))
+ {
+ return FALSE;
+ }
+
+ /* no error, but no result either */
+ if (_dbus_string_get_length(session_type) == 0)
+ {
+ return FALSE;
+ }
+
+ /* strip the carriage-return */
+ _dbus_string_shorten(session_type, 1);
+ return TRUE;
+#else /* DBUS_ENABLE_LAUNCHD */
+ dbus_set_error(error, DBUS_ERROR_NOT_SUPPORTED,
+ "can't lookup session type from launchd; launchd support not compiled in");
+ return FALSE;
+#endif
+}
+
+/**
+ * queries launchd for the current session type and checks if it matches
+ * the expected type.
+ * @param expected the expected type
+ * @param error a DBusError to store the error in case of failure
+ * @return true on success, false on error
+ */
+dbus_bool_t
+_dbus_match_launchd_session_type (const char *expected,
+ DBusError *error)
+{
+ DBusString session_type;
+ if (!_dbus_string_init (&session_type))
+ {
+ _DBUS_SET_OOM (error);
+ return FALSE;
+ }
+ if (!_dbus_lookup_launchd_session_type (&session_type, error) || dbus_error_is_set(error))
+ {
+ _dbus_string_free(&session_type);
+ return FALSE;
+ }
+ else if (!_dbus_string_equal_c_str (&session_type, expected))
+ {
+ // the launchd plist limits us to using Aqua sessions
+ dbus_set_error(error, "unexpected launchctl session type",
+ _dbus_string_get_const_data(&session_type));
+ _dbus_string_free(&session_type);
+ return FALSE;
+ }
+ _dbus_string_free(&session_type);
+ return TRUE;
+}
+
+/**
+ * queries launchd for a specific env var which holds the socket path.
* @param socket_path append the socket path to this DBusString
* @param launchd_env_var the env var to look up
* @param error a DBusError to store the error in case of failure
- * @return the value of the env var
+ * @return true on success, false on error
*/
dbus_bool_t
_dbus_lookup_launchd_socket (DBusString *socket_path,
@@ -3706,7 +3801,7 @@ _dbus_lookup_launchd_socket (DBusString *socket_path,
#ifdef DBUS_ENABLE_LAUNCHD
static dbus_bool_t
-_dbus_lookup_session_address_launchd (DBusString *address, DBusError *error)
+_dbus_lookup_session_address_launchd (dbus_bool_t *supported, DBusString *address, DBusError *error)
{
dbus_bool_t valid_socket;
DBusString socket_path;
@@ -3718,6 +3813,13 @@ _dbus_lookup_session_address_launchd (DBusString *address, DBusError *error)
return FALSE;
}
+ *supported = TRUE;
+ if (!_dbus_match_launchd_session_type("Aqua", error))
+ {
+ *supported = FALSE;
+ return FALSE;
+ }
+
if (!_dbus_string_init (&socket_path))
{
_DBUS_SET_OOM (error);
@@ -3784,8 +3886,10 @@ _dbus_lookup_session_address (dbus_bool_t *supported,
DBusError *error)
{
#ifdef DBUS_ENABLE_LAUNCHD
- *supported = TRUE;
- return _dbus_lookup_session_address_launchd (address, error);
+ dbus_bool_t retval = _dbus_lookup_session_address_launchd (supported, address, error);
+ // _dbus_lookup_session_address_launchd returns FALSE with *supported==FALSE if we're not
+ // running in an Aqua session; in that case we'll try to behave like on non-Mac Unix platforms.
+ return (!*supported)? TRUE : retval;
#else
/* On non-Mac Unix platforms, if the session address isn't already
* set in DBUS_SESSION_BUS_ADDRESS environment variable, we punt and
diff --git a/dbus/dbus-sysdeps-unix.h b/dbus/dbus-sysdeps-unix.h
index a265b33..f0a4e32 100644
--- a/dbus/dbus-sysdeps-unix.h
+++ b/dbus/dbus-sysdeps-unix.h
@@ -83,6 +83,10 @@ dbus_bool_t _dbus_read_credentials (int client_fd,
dbus_bool_t _dbus_send_credentials (int server_fd,
DBusError *error);
+dbus_bool_t _dbus_lookup_launchd_session_type (DBusString *session_type,
+ DBusError *error);
+dbus_bool_t _dbus_match_launchd_session_type (const char *expected,
+ DBusError *error);
dbus_bool_t _dbus_lookup_launchd_socket (DBusString *socket_path,
const char *launchd_env_var,
DBusError *error);