From e774af31f4e9ca7beb1d6fbac84c8fcdb8506f18 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 11 Jun 2008 16:17:33 -0400 Subject: [PATCH] Bug 14259: MacOS/launchd support This patch is based on work from Benjamin Reed and Tanner Lovelace. * bus/Makefile.am: Add plist file which sets up launchd. * bus/session.conf.in: Drop hardcoded unix:tmpdir in favor of a new scheme "default:" which says to use built-in defaults in the code. * configure.in: New --enable-launchd and --with-launchd-agent-dir. * dbus/Makefile.am: Add dbus-server-launchd files. * dbus/dbus-bus.c: Factor out function init_session_address which will make use of the new platform-specific lookup function _dbus_lookup_session_address. * dbus/dbus-server-unix.c: Add support for the launchd: method if available. * dbus/dbus-server.c: Handle the special default: address scheme which is now in the session.conf. * dbus/dbus-sysdeps-unix.c: Create new function _read_subprocess_line_argv which is used both by the autolaunch and by the launchd lookup functions. Create new function dbus_lookup_session_address_macos to call into launchd. Implement _dbus_get_default_address_template for Unix which returns launchd: on MacOS, or just unix:tmpdir otherwise. * dbus/dbus-sysdeps-win.c: Stub out new functions _dbus_lookup_session_address and _dbus_get_default_address_template with some FIXME comments about how we might use COM. * dbus/dbus-sysdeps.h: New functions for getting the address of the session bus in a platform-specific way. * dbus/dbus-server-launchd.c, dbus/dbus-server-launchd.h: New files which handle talking to launchd to take over the socket allocated by launchd. --- bus/Makefile.am | 8 +- bus/org.freedesktop.dbus-session.plist.in | 31 +++ bus/session.conf.in | 3 +- configure.in | 37 ++++ dbus/Makefile.am | 9 +- dbus/dbus-bus.c | 62 +++++- dbus/dbus-server-launchd.c | 149 ++++++++++++++ dbus/dbus-server-launchd.h | 37 ++++ dbus/dbus-server-unix.c | 25 +++ dbus/dbus-server.c | 18 ++ dbus/dbus-sysdeps-unix.c | 300 +++++++++++++++++++++++++---- dbus/dbus-sysdeps-win.c | 23 ++- dbus/dbus-sysdeps.h | 6 + 13 files changed, 660 insertions(+), 48 deletions(-) create mode 100644 bus/org.freedesktop.dbus-session.plist.in create mode 100644 dbus/dbus-server-launchd.c create mode 100644 dbus/dbus-server-launchd.h diff --git a/bus/Makefile.am b/bus/Makefile.am index 3b4f69d..420742b 100644 --- a/bus/Makefile.am +++ b/bus/Makefile.am @@ -9,12 +9,18 @@ EFENCE= CONFIG_IN_FILES= \ session.conf.in \ - system.conf.in + system.conf.in \ + org.freedesktop.dbus-session.plist.in config_DATA= \ session.conf \ system.conf +if DBUS_ENABLE_LAUNCHD +agentdir=$(LAUNCHD_AGENT_DIR) +agent_DATA=org.freedesktop.dbus-session.plist +endif + if DBUS_USE_LIBXML XML_SOURCES=config-loader-libxml.c endif diff --git a/bus/org.freedesktop.dbus-session.plist.in b/bus/org.freedesktop.dbus-session.plist.in new file mode 100644 index 0000000..6f1ad8e --- /dev/null +++ b/bus/org.freedesktop.dbus-session.plist.in @@ -0,0 +1,31 @@ + + + + + Label + org.freedesktop.dbus-session + + ServiceIPC + + + + OnDemand + + + ProgramArguments + + @DBUS_DAEMONDIR@/dbus-daemon + --nofork + --session + + + Sockets + + session + + SecureSocketWithKey + DBUS_LAUNCHD_SESSION_BUS_SOCKET + + + + diff --git a/bus/session.conf.in b/bus/session.conf.in index b2dee5b..276a8b4 100644 --- a/bus/session.conf.in +++ b/bus/session.conf.in @@ -8,7 +8,8 @@ session - unix:tmpdir=@DBUS_SESSION_SOCKET_DIR@ + + default:type=session diff --git a/configure.in b/configure.in index b833840..acf27e9 100644 --- a/configure.in +++ b/configure.in @@ -78,6 +78,7 @@ AC_ARG_ENABLE(inotify, AS_HELP_STRING([--enable-inotify],[build with inotify sup AC_ARG_ENABLE(kqueue, AS_HELP_STRING([--enable-kqueue],[build with kqueue support]),enable_kqueue=$enableval,enable_kqueue=auto) AC_ARG_ENABLE(console-owner-file, AS_HELP_STRING([--enable-console-owner-file],[enable console owner file]),enable_console_owner_file=$enableval,enable_console_owner_file=auto) AC_ARG_ENABLE(userdb-cache, AS_HELP_STRING([--enable-userdb-cache],[build with userdb-cache support]),enable_userdb_cache=$enableval,enable_userdb_cache=yes) +AC_ARG_ENABLE(launchd, AS_HELP_STRING([--enable-launchd],[build with launchd auto-launch support]),enable_launchd=$enableval,enable_launchd=auto) AC_ARG_WITH(xml, AS_HELP_STRING([--with-xml=[libxml/expat]],[XML library to use])) AC_ARG_WITH(init-scripts, AS_HELP_STRING([--with-init-scripts=[redhat]],[Style of init scripts to install])) @@ -87,6 +88,7 @@ AC_ARG_WITH(system-pid-file, AS_HELP_STRING([--with-system-pid-file=[pidfile]],[ AC_ARG_WITH(system-socket, AS_HELP_STRING([--with-system-socket=[filename]],[UNIX domain socket for systemwide daemon])) AC_ARG_WITH(console-auth-dir, AS_HELP_STRING([--with-console-auth-dir=[dirname]],[directory to check for console ownerhip])) AC_ARG_WITH(console-owner-file, AS_HELP_STRING([--with-console-owner-file=[filename]],[file whose owner determines current console owner])) +AC_ARG_WITH(launchd-agent-dir, AS_HELP_STRING([--with-launchd-agent-dir=[dirname]],[directory to put the launchd agent (default: /Library/LaunchAgents)])) AC_ARG_WITH(dbus_user, AS_HELP_STRING([--with-dbus-user=],[User for running the DBUS daemon (messagebus)])) AC_ARG_WITH(dbus_daemondir, AS_HELP_STRING([--with-dbus-daemondir=[dirname]],[Directory for installing the DBUS daemon])) @@ -991,6 +993,38 @@ fi AM_CONDITIONAL(DBUS_BUS_ENABLE_KQUEUE, test x$have_kqueue = xyes) +# launchd checks +if test x$enable_launchd = xno ; then + have_launchd=no +else + have_launchd=yes + AC_CHECK_HEADER([launch.h], , have_launchd=no) + AC_PATH_PROG([LAUNCHCTL], [launchctl]) + if test "x$LAUNCHCTL" = "x"; then + have_launchd=no + fi + + if test x$enable_launchd = xyes -a x$have_launchd = xno ; then + AC_MSG_ERROR([launchd support explicitly enabled but not available]) + fi +fi + +dnl check if launchd is enabled +if test x$have_launchd = xyes; then + AC_DEFINE(DBUS_ENABLE_LAUNCHD,1,[Use launchd autolaunch]) +fi + +AM_CONDITIONAL(DBUS_ENABLE_LAUNCHD, test x$have_launchd = xyes) + +#### Directory to place launchd agent file +if test "x$with_launchd_agent_dir" = "x"; then + LAUNCHD_AGENT_DIR="/Library/LaunchAgents" +else + LAUNCHD_AGENT_DIR="$with_launchd_agent_dir" +fi + +AC_SUBST(LAUNCHD_AGENT_DIR) + dnl console owner file if test x$enable_console_owner_file = xno ; then have_console_owner_file=no; @@ -1352,6 +1386,7 @@ dbus/dbus-arch-deps.h bus/system.conf bus/session.conf bus/messagebus +bus/org.freedesktop.dbus-session.plist bus/rc.messagebus bus/dbus-daemon.1 Makefile @@ -1419,6 +1454,7 @@ echo " Building Doxygen docs: ${enable_doxygen_docs} Building XML docs: ${enable_xml_docs} Building cache support: ${enable_userdb_cache} + Building launchd support: ${have_launchd} Gettext libs (empty OK): ${INTLLIBS} Using XML parser: ${with_xml} Init scripts style: ${with_init_scripts} @@ -1433,6 +1469,7 @@ echo " System bus user: ${DBUS_USER} Session bus services dir: ${EXPANDED_DATADIR}/dbus-1/services 'make check' socket dir: ${TEST_SOCKET_DIR} + launchd agent dir: ${LAUNCHD_AGENT_DIR} " if test x$enable_tests = xyes; then diff --git a/dbus/Makefile.am b/dbus/Makefile.am index e966a43..3a9c3ad 100644 --- a/dbus/Makefile.am +++ b/dbus/Makefile.am @@ -9,6 +9,12 @@ INCLUDES=-I$(top_builddir) -I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) @PIC_CFLAGS@ -D dbusincludedir=$(includedir)/dbus-1.0/dbus dbusarchincludedir=$(libdir)/dbus-1.0/include/dbus +if DBUS_ENABLE_LAUNCHD +LAUNCHD_SOURCES = \ + dbus-server-launchd.h \ + dbus-server-launchd.c +endif + lib_LTLIBRARIES=libdbus-1.la dbusinclude_HEADERS= \ @@ -92,7 +98,8 @@ DBUS_LIB_SOURCES= \ dbus-uuidgen.c \ dbus-uuidgen.h \ dbus-watch.c \ - dbus-watch.h + dbus-watch.h \ + $(LAUNCHD_SOURCES) ## dbus-md5.c \ ## dbus-md5.h \ diff --git a/dbus/dbus-bus.c b/dbus/dbus-bus.c index f97cce6..6fbd3c1 100644 --- a/dbus/dbus-bus.c +++ b/dbus/dbus-bus.c @@ -22,6 +22,7 @@ * */ +#include #include "dbus-bus.h" #include "dbus-protocol.h" #include "dbus-internals.h" @@ -29,6 +30,7 @@ #include "dbus-marshal-validate.h" #include "dbus-threads-internal.h" #include "dbus-connection-internal.h" +#include "dbus-string.h" #include /** @@ -147,6 +149,56 @@ get_from_env (char **connection_p, } static dbus_bool_t +init_session_address (void) +{ + dbus_bool_t retval; + + retval = FALSE; + + /* First, look in the environment. This is the normal case on + * freedesktop.org/Unix systems. */ + if (!get_from_env (&bus_connection_addresses[DBUS_BUS_SESSION], + "DBUS_SESSION_BUS_ADDRESS")) + { + dbus_bool_t supported; + DBusString addr; + + if (!_dbus_string_init (&addr)) + return FALSE; + + supported = FALSE; + /* So it's not in the environment - let's try a platform-specific method. + * On MacOS, this involves asking launchd. On Windows (not specified yet) + * we might do a COM lookup. + * Ignore errors - if we failed, fall back to autolaunch. */ + retval = _dbus_lookup_session_address (&supported, &addr, NULL); + if (supported && retval) + { + retval =_dbus_string_steal_data (&addr, &bus_connection_addresses[DBUS_BUS_SESSION]); + } + else if (supported && !retval) + _dbus_warn ("Dynamic session lookup supported but failed"); + _dbus_string_free (&addr); + } + else + retval = TRUE; + + if (!retval) + return FALSE; + + /* The DBUS_SESSION_BUS_DEFAULT_ADDRESS should have really been named + * DBUS_SESSION_BUS_FALLBACK_ADDRESS. + */ + if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL) + bus_connection_addresses[DBUS_BUS_SESSION] = + _dbus_strdup (DBUS_SESSION_BUS_DEFAULT_ADDRESS); + if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL) + return FALSE; + + return TRUE; +} + +static dbus_bool_t init_connections_unlocked (void) { if (!initialized) @@ -198,17 +250,9 @@ init_connections_unlocked (void) { _dbus_verbose ("Filling in session bus address...\n"); - if (!get_from_env (&bus_connection_addresses[DBUS_BUS_SESSION], - "DBUS_SESSION_BUS_ADDRESS")) + if (!init_session_address ()) return FALSE; - - if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL) - bus_connection_addresses[DBUS_BUS_SESSION] = - _dbus_strdup (DBUS_SESSION_BUS_DEFAULT_ADDRESS); - if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL) - return FALSE; - _dbus_verbose (" \"%s\"\n", bus_connection_addresses[DBUS_BUS_SESSION] ? bus_connection_addresses[DBUS_BUS_SESSION] : "none set"); } diff --git a/dbus/dbus-server-launchd.c b/dbus/dbus-server-launchd.c new file mode 100644 index 0000000..5109fbb --- /dev/null +++ b/dbus/dbus-server-launchd.c @@ -0,0 +1,149 @@ +/* dbus-server-launchd.c Server methods for interacting with launchd. + * Copyright (C) 2007, Tanner Lovelace + * Copyright (C) 2008, Benjamin Reed + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#include "dbus-server-socket.h" +#include "dbus-server-launchd.h" + +/** + * @defgroup DBusServerLaunchd DBusServer implementations for Launchd + * @ingroup DBusInternals + * @brief Implementation details of DBusServer with Launchd support + * + * @{ + */ + +/** + * Creates a new server from launchd. + * + * @param socket_key they key to use when looking up the file descriptor from launchd + * @param error location to store reason for failure. + * @returns the new server, or #NULL on failure. + */ + +DBusServer* +_dbus_server_new_for_launchd_fd (const char *socket_key, DBusError *error) +{ + DBusServer *server; + DBusString address; + int launchd_fd; + launch_data_t sockets_dict, checkin_response; + launch_data_t checkin_request; + launch_data_t listening_fd_array, listening_fd; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (!_dbus_string_init (&address)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } + if (!_dbus_string_append (&address, "launchd:key=")) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto l_failed_0; + } + if (!_dbus_string_append (&address, socket_key)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto l_failed_0; + } + + if ((checkin_request = launch_data_new_string (LAUNCH_KEY_CHECKIN)) == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, + "launch_data_new_string(\"%s\") Unable to create string.\n", LAUNCH_KEY_CHECKIN); + goto l_failed_0; + } + + if ((checkin_response = launch_msg (checkin_request)) == NULL) + { + dbus_set_error (error, DBUS_ERROR_IO_ERROR, "launch_msg(\"%s\") IPC failure: %s\n", + LAUNCH_KEY_CHECKIN, strerror (errno)); + goto l_failed_0; + } + + if (LAUNCH_DATA_ERRNO == launch_data_get_type (checkin_response)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, "Check-in failed: %s\n", + strerror (launch_data_get_errno (checkin_response))); + goto l_failed_0; + } + + sockets_dict = launch_data_dict_lookup (checkin_response, LAUNCH_JOBKEY_SOCKETS); + if (NULL == sockets_dict) + { + dbus_set_error (error, DBUS_ERROR_IO_ERROR, "No sockets found to answer requests on!\n"); + goto l_failed_0; + } + + listening_fd_array = launch_data_dict_lookup (sockets_dict, socket_key); + if (NULL == listening_fd_array) + { + dbus_set_error (error, DBUS_ERROR_IO_ERROR, "No known sockets found to answer requests on!\n"); + goto l_failed_0; + } + + if (launch_data_array_get_count (listening_fd_array) != 1) + { + dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, + "Expected 1 socket from launchd, got %d.\n", + launch_data_array_get_count (listening_fd_array)); + goto l_failed_0; + } + + listening_fd = launch_data_array_get_index (listening_fd_array, 0); + launchd_fd = launch_data_get_fd (listening_fd); + + _dbus_fd_set_close_on_exec (launchd_fd); + + if (launchd_fd < 0) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto l_failed_0; + } + + server = _dbus_server_new_for_socket (&launchd_fd, 1, &address); + if (server == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_SERVER, "Unable to listen on launchd fd %d.", launchd_fd); + goto l_failed_0; + } + + _dbus_string_free (&address); + + return server; + + l_failed_0: + _dbus_string_free (&address); + + return NULL; +} + +/** @} */ + diff --git a/dbus/dbus-server-launchd.h b/dbus/dbus-server-launchd.h new file mode 100644 index 0000000..1c45aa1 --- /dev/null +++ b/dbus/dbus-server-launchd.h @@ -0,0 +1,37 @@ +/* dbus-server-launchd.h Server methods for interacting with launchd. +* Copyright (C) 2008, Benjamin Reed +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, +* modify, merge, publish, distribute, sublicense, and/or sell copies +* of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +* DEALINGS IN THE SOFTWARE. +*/ + +#ifndef DBUS_SERVER_LAUNCHD_H +#define DBUS_SERVER_LAUNCHD_H + +#include +#include + +DBUS_BEGIN_DECLS + +DBusServer* _dbus_server_new_for_launchd_fd (const char *socket_fd, DBusError *error); + +DBUS_END_DECLS + +#endif /* DBUS_SERVER_LAUNCHD_H */ diff --git a/dbus/dbus-server-unix.c b/dbus/dbus-server-unix.c index 1dda5d1..e05f174 100644 --- a/dbus/dbus-server-unix.c +++ b/dbus/dbus-server-unix.c @@ -21,6 +21,7 @@ * */ +#include #include "dbus-internals.h" #include "dbus-server-unix.h" #include "dbus-server-socket.h" @@ -29,6 +30,10 @@ #include "dbus-sysdeps-unix.h" #include "dbus-string.h" +#ifdef DBUS_ENABLE_LAUNCHD +#include "dbus-server-launchd.h" +#endif + /** * @defgroup DBusServerUnix DBusServer implementations for UNIX * @ingroup DBusInternals @@ -145,6 +150,26 @@ _dbus_server_listen_platform_specific (DBusAddressEntry *entry, return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } } +#ifdef DBUS_ENABLE_LAUNCHD + else if (strcmp (method, "launchd") == 0) + { + const char *launchd_key = dbus_address_entry_get_value (entry, "key"); + if (launchd_key == NULL) + launchd_key = "session"; + *server_p = _dbus_server_new_for_launchd_fd (launchd_key, error); + + if (*server_p != NULL) + { + _DBUS_ASSERT_ERROR_IS_CLEAR(error); + return DBUS_SERVER_LISTEN_OK; + } + else + { + _DBUS_ASSERT_ERROR_IS_SET(error); + return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; + } + } +#endif else { /* If we don't handle the method, we return NULL with the diff --git a/dbus/dbus-server.c b/dbus/dbus-server.c index f04829b..985b08a 100644 --- a/dbus/dbus-server.c +++ b/dbus/dbus-server.c @@ -530,6 +530,11 @@ static const struct { * * To free the server, applications must call first * dbus_server_disconnect() and then dbus_server_unref(). + * + * There is special support for built-in platform-specific address types; + * these are denoted with the prefix "default:", and a "type" parameter + * specifying the kind of default. For example, "default:type=session" + * uses the platform-specific default for the session bus. * * @param address the address of this server. * @param error location to store reason for failure. @@ -548,6 +553,19 @@ dbus_server_listen (const char *address, _dbus_return_val_if_fail (address != NULL, NULL); _dbus_return_val_if_error_is_set (error, NULL); + + /* If a default: type is specified, this means to use a + * platform-specific built-in address type. We just use + * a plain strcmp here since we don't need all the + * parsing machinery really. + */ + if (strcmp (address, "default:type=session") == 0) + { + const char *default_address; + default_address = _dbus_get_default_address_template ("session"); + if (default_address != NULL) + address = default_address; + } if (!dbus_parse_address (address, &entries, &len, error)) return NULL; diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c index 64d925d..eff4720 100644 --- a/dbus/dbus-sysdeps-unix.c +++ b/dbus/dbus-sysdeps-unix.c @@ -75,6 +75,10 @@ #include #endif +#ifdef DBUS_ENABLE_LAUNCHD +#include +#endif + #ifndef O_BINARY #define O_BINARY 0 #endif @@ -2789,22 +2793,26 @@ _dbus_get_tmpdir(void) } /** - * Determines the address of the session bus by querying a - * platform-specific method. + * Execute a subprocess, returning up to 1024 bytes of output + * into address. * - * If successful, returns #TRUE and appends the address to @p + * If successful, returns #TRUE and appends the output to @p * address. If a failure happens, returns #FALSE and * sets an error in @p error. * - * @param address a DBusString where the address can be stored + * @param progname initial path to exec + * @param fallback_with_path if exec fails, use this program name on PATH + * @param argv NULL-terminated list of arguments + * @param address a DBusString where the output can be stored * @param error a DBusError to store the error in case of failure * @returns #TRUE on success, #FALSE if an error happened */ -dbus_bool_t -_dbus_get_autolaunch_address (DBusString *address, - DBusError *error) +static dbus_bool_t +_read_subprocess_line_argv (const char *progpath, + const char * const *argv, + DBusString *address, + DBusError *error) { - static char *argv[6]; int address_pipe[2] = { -1, -1 }; int errors_pipe[2] = { -1, -1 }; pid_t pid; @@ -2814,6 +2822,7 @@ _dbus_get_autolaunch_address (DBusString *address, int i; DBusString uuid; dbus_bool_t retval; + const char *progname; _DBUS_ASSERT_ERROR_IS_CLEAR (error); retval = FALSE; @@ -2823,29 +2832,7 @@ _dbus_get_autolaunch_address (DBusString *address, _DBUS_SET_OOM (error); return FALSE; } - - if (!_dbus_get_local_machine_uuid_encoded (&uuid)) - { - _DBUS_SET_OOM (error); - goto out; - } - - i = 0; - argv[i] = "dbus-launch"; - ++i; - argv[i] = "--autolaunch"; - ++i; - argv[i] = _dbus_string_get_data (&uuid); - ++i; - argv[i] = "--binary-syntax"; - ++i; - argv[i] = "--close-stderr"; - ++i; - argv[i] = NULL; - ++i; - _dbus_assert (i == _DBUS_N_ELEMENTS (argv)); - orig_len = _dbus_string_get_length (address); #define READ_END 0 @@ -2916,11 +2903,22 @@ _dbus_get_autolaunch_address (DBusString *address, /* close all inherited fds */ for (i = 3; i < maxfds; i++) close (i); - - execv (DBUS_BINDIR "/dbus-launch", argv); - - /* failed, try searching PATH */ - execvp ("dbus-launch", argv); + + /* If it looks fully-qualified, try execv first */ + if (progpath[0] == '/') + { + const char *progname; + + execv (progpath, argv); + + /* If we failed with a direct exec, try extracting + the binary name and search the PATH for it */ + progname = strrchr (progpath, '/'); + if (progname != NULL) + execvp (progname+1, argv); + } + else + execvp (progpath, argv); /* still nothing, we failed */ _exit (1); @@ -2989,10 +2987,155 @@ _dbus_get_autolaunch_address (DBusString *address, if (errors_pipe[1] != -1) close (errors_pipe[1]); + return retval; +} + +/** + * Returns the address of a new session bus. + * + * If successful, returns #TRUE and appends the address to @p + * address. If a failure happens, returns #FALSE and + * sets an error in @p error. + * + * @param address a DBusString where the address can be stored + * @param error a DBusError to store the error in case of failure + * @returns #TRUE on success, #FALSE if an error happened + */ +dbus_bool_t +_dbus_get_autolaunch_address (DBusString *address, + DBusError *error) +{ + static char *argv[6]; + int i; + DBusString uuid; + dbus_bool_t retval; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + retval = FALSE; + + if (!_dbus_string_init (&uuid)) + { + _DBUS_SET_OOM (error); + return FALSE; + } + + if (!_dbus_get_local_machine_uuid_encoded (&uuid)) + { + _DBUS_SET_OOM (error); + goto out; + } + + i = 0; + argv[i] = "dbus-launch"; + ++i; + argv[i] = "--autolaunch"; + ++i; + argv[i] = _dbus_string_get_data (&uuid); + ++i; + argv[i] = "--binary-syntax"; + ++i; + argv[i] = "--close-stderr"; + ++i; + argv[i] = NULL; + ++i; + + _dbus_assert (i == _DBUS_N_ELEMENTS (argv)); + + retval = _read_subprocess_line_argv (address, error, + DBUS_BINDIR "/dbus-launch", + argv); + out: _dbus_string_free (&uuid); return retval; } +#ifdef DBUS_ENABLE_LAUNCHD +static dbus_bool_t +_dbus_lookup_session_address_macos (DBusString *address, + DBusError *error) +{ + static char *argv[4]; + int i; + DBusString uuid; + dbus_bool_t retval; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + i = 0; + argv[i] = "launchd"; + ++i; + argv[i] = "getenv"; + ++i; + argv[i] = "DBUS_LAUNCHD_SESSION_BUS_SOCKET"; + ++i; + argv[i] = NULL; + ++i; + + _dbus_assert (i == _DBUS_N_ELEMENTS (argv)); + + return _read_subprocess_line_argv (address, error, + "launchd", + argv); +} +#endif + +/** + * Determines the address of the session bus by querying a + * platform-specific method. + * + * The first parameter will be a boolean specifying whether + * or not a dynamic session lookup is supported on this platform. + * + * If supported is TRUE and the return value is #TRUE, the + * address will be appended to @p address. + * If a failure happens, returns #FALSE and sets an error in + * @p error. + * + * If supported is FALSE, ignore the return value. + * + * @param address a DBusString where the address can be stored + * @param error a DBusError to store the error in case of failure + * @returns #TRUE on success, #FALSE if an error happened + */ +dbus_bool_t +_dbus_lookup_session_address (dbus_bool_t *supported, + DBusString *address, + DBusError *error) +{ +#ifdef DBUS_ENABLE_LAUNCHD + *supported = TRUE; + return _dbus_lookup_session_address_macos (address, error); +#else + /* On non-Mac Unix platforms, if the session address isn't already + * set in DBUS_SESSION_BUS_ADDRESS environment variable, we punt and + * fall back to the autolaunch: global default; see + * init_session_address in dbus/dbus-bus.c. */ + *supported = FALSE; + return TRUE; +#endif +} + +/** + * Creates a platform-specific server address template from + * a default:bustype address. + * + * @param type a string such as "session" specifying the kind of bus + * @returns NULL if type is unknown, otherwise a session address template + */ +const char * +_dbus_get_default_address_template (const char *type) +{ + if (strcmp (type, "session") == 0) + { +#ifdef DBUS_ENABLE_LAUNCHD + return "launchd:" +#else + return "unix:tmpdir=" DBUS_SESSION_SOCKET_DIR; +#endif + } + return NULL; +} + /** * Reads the uuid of the machine we're running on from * the dbus configuration. Optionally try to create it @@ -3307,4 +3450,91 @@ _dbus_get_is_errno_eagain_or_ewouldblock (void) return errno == EAGAIN || errno == EWOULDBLOCK; } +#ifdef DBUS_ENABLE_LAUNCHD +/** + * Initialization for turning a launchd environment into + * DBUS_SESSION_BUS_ADDRESS + */ +void +_dbus_unix_launchd_initialize_environment (void) +{ + FILE *launchd = NULL; + const char *env_var = NULL; + char launchctl_output[DBUS_LAUNCHD_MAX_OUTPUT_LINE]; + DBusString socket_filename; + DBusString session_address; + + if (!_dbus_string_init (&socket_filename)) + { + return; + } + + if (!_dbus_string_init (&session_address)) + goto launchd_finished_0; + + /* + * Try to get the dbus session bus address + */ + env_var = _dbus_getenv("DBUS_SESSION_BUS_ADDRESS"); + + /* + * User has already overridden in the environment. + * Use that directly. + */ + if (env_var != NULL && (strlen(env_var) > 0)) + goto launchd_finished_1; + + /* + * User doesn't have the session buss address set + * so let's try to get it from launchd. + */ + env_var = _dbus_getenv("DBUS_LAUNCHD_SESSION_BUS_SOCKET"); + + if (env_var == NULL || (strlen(env_var) == 0) || access(env_var, W_OK) != 0) + { + /* + * This is a bit of a kludge but it works on both OS X Tiger & Leopard. + */ + launchd = popen("launchctl getenv DBUS_LAUNCHD_SESSION_BUS_SOCKET", "r"); + if (launchd != NULL && !feof(launchd)) + { + if (_dbus_read(fileno(launchd), &socket_filename, DBUS_LAUNCHD_MAX_OUTPUT_LINE) > 0) + { + // strip the carriage-return + _dbus_string_shorten(&socket_filename, 1); + + env_var = _dbus_string_get_data(&socket_filename); + } + } + /* + * Make sure launchd file is closed. + */ + if (launchd != NULL) + pclose(launchd); + } + + /* + * Now that we have the session socket from launchd, set the + * DBUS_SESSION_BUS_ADDRESS environment variable. + */ + if (env_var != NULL && strlen(env_var) != 0 && access(env_var, W_OK) == 0) + { + if (!_dbus_string_append (&session_address, "unix:path=")) + goto launchd_finished_1; + + if (!_dbus_string_append (&session_address, env_var)) + goto launchd_finished_1; + + _dbus_setenv("DBUS_SESSION_BUS_ADDRESS", _dbus_string_get_const_data(&session_address)); + } + + launchd_finished_1: + _dbus_string_free(&session_address); + + launchd_finished_0: + _dbus_string_free(&socket_filename); +} +#endif + + /* tests in dbus-sysdeps-util.c */ diff --git a/dbus/dbus-sysdeps-win.c b/dbus/dbus-sysdeps-win.c index a67e502..486b17b 100644 --- a/dbus/dbus-sysdeps-win.c +++ b/dbus/dbus-sysdeps-win.c @@ -1393,8 +1393,29 @@ _dbus_poll (DBusPollFD *fds, #endif // USE_CHRIS_IMPL +dbus_bool_t +_dbus_lookup_session_address (dbus_bool_t *supported, + DBusString *address, + DBusError *error) +{ + /* FIXME - implement this by querying COM or some other Windows facility + * which is scoped per-session. + */ + *supported = FALSE; + return TRUE; +} - +const char * +_dbus_get_default_address_template (const char *type) +{ + if (strcmp (type, "session") == 0) + { + /* FIXME - this is an not-implemented hypothetical address format + * which says to store the session address in COM + */ + return "w32com:scope=SESSION,key=DBUS_SESSION"; + } +} /****************************************************************************** diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h index 5ff1388..65646f3 100644 --- a/dbus/dbus-sysdeps.h +++ b/dbus/dbus-sysdeps.h @@ -457,6 +457,12 @@ dbus_bool_t _dbus_user_at_console (const char *username, dbus_bool_t _dbus_get_autolaunch_address (DBusString *address, DBusError *error); +dbus_bool_t _dbus_lookup_session_address (dbus_bool_t *supported, + DBusString *address, + DBusError *error); + +const char * _dbus_get_default_address_template (const char *type); + /** Type representing a universally unique ID * @todo rename to UUID instead of GUID */ -- 1.5.5.1