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..ea29849 100644
--- a/bus/session.conf.in
+++ b/bus/session.conf.in
@@ -8,7 +8,7 @@
session
- unix:tmpdir=@DBUS_SESSION_SOCKET_DIR@
+ @DBUS_SESSION_BUS_DEFAULT_ADDRESS@
diff --git a/configure.in b/configure.in
index d38f6d9..fa94197 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;
@@ -1313,6 +1347,13 @@ fi
AC_DEFINE_UNQUOTED(DBUS_SESSION_SOCKET_DIR, "$DBUS_SESSION_SOCKET_DIR", [Where per-session bus puts its sockets])
AC_SUBST(DBUS_SESSION_SOCKET_DIR)
+if test x$have_launchd = xyes; then
+ DBUS_SESSION_BUS_DEFAULT_ADDRESS="autolaunch:"
+else
+ DBUS_SESSION_BUS_DEFAULT_ADDRESS="unix:tmpdir=$DBUS_SESSION_SOCKET_DIR"
+fi
+AC_SUBST(DBUS_SESSION_BUS_DEFAULT_ADDRESS)
+
AC_DEFINE_UNQUOTED(DBUS_UNIX, "1", [Defined on UNIX and Linux systems and not on Windows])
# darwin needs this to initialize the environment
@@ -1333,6 +1374,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
@@ -1399,6 +1441,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}
@@ -1413,6 +1456,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 e159dae..dd0ff4e 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"
@@ -159,6 +160,10 @@ init_connections_unlocked (void)
++i;
}
+#ifdef DBUS_ENABLE_LAUNCHD
+ _dbus_unix_launchd_initialize_environment();
+#endif
+
/* Don't init these twice, we may run this code twice if
* init_connections_unlocked() fails midway through.
* In practice, each block below should contain only one
diff --git a/dbus/dbus-server-launchd.c b/dbus/dbus-server-launchd.c
new file mode 100644
index 0000000..fce274b
--- /dev/null
+++ b/dbus/dbus-server-launchd.c
@@ -0,0 +1,138 @@
+/* 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, "autolaunch: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..ddc0944 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,27 @@ _dbus_server_listen_platform_specific (DBusAddressEntry *entry,
return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
}
}
+#ifdef DBUS_ENABLE_LAUNCHD
+ else if (strcmp (method, "autolaunch") == 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-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c
index 19858dd..5bc600d 100644
--- a/dbus/dbus-sysdeps-unix.c
+++ b/dbus/dbus-sysdeps-unix.c
@@ -71,6 +71,11 @@
#include
#endif
+#ifdef DBUS_ENABLE_LAUNCHD
+#include
+#define DBUS_LAUNCHD_MAX_OUTPUT_LINE MAXPATHLEN + 2
+#endif
+
#ifndef O_BINARY
#define O_BINARY 0
#endif
@@ -3263,4 +3268,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-unix.h b/dbus/dbus-sysdeps-unix.h
index 0005cd8..b0ba860 100644
--- a/dbus/dbus-sysdeps-unix.h
+++ b/dbus/dbus-sysdeps-unix.h
@@ -127,6 +127,13 @@ dbus_gid_t _dbus_getgid (void);
dbus_bool_t _dbus_parse_uid (const DBusString *uid_str,
dbus_uid_t *uid);
+/**
+ * Initialization for turning a launchd environment into
+ * DBUS_SESSION_BUS_ADDRESS
+ */
+void
+_dbus_unix_launchd_initialize_environment (void);
+
/** @} */
DBUS_END_DECLS