Enable launchd.
authorBenjamin Reed <rangerrick@befunk.com>
Sun, 19 Jul 2009 15:45:34 +0000 (11:45 -0400)
committerRalf Habacker <ralf.habacker@freenet.de>
Mon, 6 Dec 2010 20:33:14 +0000 (21:33 +0100)
This patch enables support for Mac OS X's launch daemon
for startup as well as sharing of the DBus session bus
environment.  It includes a LaunchAgent plist for automatic
start of the session bus.

README.launchd [new file with mode: 0644]
bus/Makefile.am
bus/org.freedesktop.dbus-session.plist.in [new file with mode: 0644]
configure.in
dbus/Makefile.am
dbus/dbus-server-unix.c
dbus/dbus-sysdeps-unix.h
dbus/dbus-transport-unix.c

diff --git a/README.launchd b/README.launchd
new file mode 100644 (file)
index 0000000..701e57d
--- /dev/null
@@ -0,0 +1,61 @@
+Launchd[1,2] replaces init, inetd and cron on Mac OS X since 10.4 "Tiger".
+dbus uses this service to provide a common session bus address for each user
+and so deprecates the X11 enabled dbus-launcher.
+
+[1] http://developer.apple.com/MacOsX/launchd.html
+[2] http://launchd.macosforge.org/
+
+
+Setup
+===
+
+Configure with --enable-launchd and --without-x (X11 should not harm but it's
+simply not necessary any more)
+After installation, to prevent a reboot, load the dbus session starter into
+launchd by executing:
+$ launchctl load /Library/LaunchAgents/org.freedesktop.dbus-session.plist
+
+You can change the launch agent dir via configure, but it's not recommended.
+Make sure to execute the above line as the actual user for which you want to
+use a session bus since launchd manages its agents on a per user basis.
+
+
+How it works
+===
+
+Launchd allocates a socket and provides the unix path to it via the variable
+DBUS_LAUNCHD_SESSION_BUS_SOCKET in launchd's environment. Every process
+spawned by launchd (or dbus-daemon, if stared by launchd) can access it through
+its own environment. Other processes can query launchd for it by executing:
+$ launchctl getenv DBUS_LAUNCHD_SESSION_BUS_SOCKET
+However, this is normally done by the dbus client lib for you.
+
+If launchd start dbus-daemon with a config file containing a "launchd:env=FOO"
+address, as the default session config does with env=DBUS_LAUNCHD_SESSION_BUS_SOCKET,
+the daemon will get the file descriptor from launchd and start listening on it.
+The environment variable is used to get the actual socket path which is passed
+to every service spawned by dbus-daemon as a result from autolaunch messages.
+Please note that it's not possible to start dbus-daemon manually when using a
+"launchd:" address. Only child processes of launchd can access the above
+mentioned file descriptor!
+
+To create custom buses just set up an other launch agent. As a quick start copy
+/Library/LaunchAgents/org.freedesktop.dbus-session.plist, change the label
+to i.e. "org.freedesktop.dbus-foo" and change the SecureSocketWithKey value,
+i.e. to "DBUS_LAUNCHD_FOO_BUS_SOCKET". This environment variable has to be set
+in the config file for your new bus in the <listen> element (see session.config).
+Then edit your /Library/LaunchAgents/org.freedesktop.dbus-foo.plist to start
+dbus-daemon with "--config-file=/opt/local/etc/dbus-1/foo.conf" instead of
+"--session". Now load the new plist onto launchd as described in the setup
+section of this document.
+Executing "launchctl export" should now give you two sockets, one in
+DBUS_LAUNCHD_SESSION_BUS_SOCKET and the new DBUS_LAUNCHD_FOO_BUS_SOCKET.
+To connect to this new bus use "launchd:env=DBUS_LAUNCHD_FOO_BUS_SOCKET".
+
+Since Mac OS X 10.5 "Leopard" you can also configure launchd to start
+dbus-daemon on demand as soon as some process connects to the socket. Since
+it's broken on 10.4 this feature is disabled per default. Look at
+/Library/LaunchAgents/org.freedesktop.dbus-session.plist to change it.
+
+On the client side, the envvar DBUS_SESSION_BUS_ADDRESS can be normally used
+but if it's not set, launchd is queried for the session bus socket.
index 17c0df8..efa8ab5 100644 (file)
@@ -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 (file)
index 0000000..ac5a9d4
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>Label</key>
+       <string>org.freedesktop.dbus-session</string>
+
+       <key>ServiceIPC</key>
+       <true/>
+
+       <!-- bug in 10.4's launchd - on-demand loading does not work -->
+       <key>OnDemand</key>
+       <false />
+
+       <key>ProgramArguments</key>
+       <array>
+               <string>@DBUS_DAEMONDIR@/dbus-daemon</string>
+               <string>--nofork</string>
+               <string>--session</string>
+       </array>
+
+       <key>Sockets</key>
+       <dict>
+               <key>unix_domain_listener</key>
+               <dict>
+                       <key>SecureSocketWithKey</key>
+                       <string>DBUS_LAUNCHD_SESSION_BUS_SOCKET</string>
+               </dict>
+       </dict>
+</dict>
+</plist>
index 98d5700..c4e36a9 100644 (file)
@@ -137,6 +137,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]))
@@ -146,6 +147,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>],[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]))
 
@@ -924,6 +926,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 && test 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;
@@ -1563,6 +1597,8 @@ AC_SUBST(DBUS_SESSION_SOCKET_DIR)
 
 if test x$dbus_win = xyes; then
         DBUS_SESSION_BUS_DEFAULT_ADDRESS="nonce-tcp:"
+elif test x$have_launchd = xyes; then
+        DBUS_SESSION_BUS_DEFAULT_ADDRESS="launchd:env=DBUS_LAUNCHD_SESSION_BUS_SOCKET"
 else
         DBUS_SESSION_BUS_DEFAULT_ADDRESS="unix:tmpdir=$DBUS_SESSION_SOCKET_DIR"
 fi
@@ -1588,6 +1624,7 @@ bus/system.conf
 bus/session.conf
 bus/messagebus
 bus/messagebus-config
+bus/org.freedesktop.dbus-session.plist
 bus/rc.messagebus
 bus/dbus.service
 bus/dbus.socket
@@ -1659,6 +1696,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}
@@ -1674,6 +1712,10 @@ echo "
        Session bus services dir: ${EXPANDED_DATADIR}/dbus-1/services
         'make check' socket dir:  ${TEST_SOCKET_DIR}
 "
+if test x$have_launchd = xyes; then
+        echo "        launchd agent dir:        ${LAUNCHD_AGENT_DIR}"
+fi
+echo
 
 if test x$enable_tests = xyes; then
         echo "NOTE: building with unit tests increases the size of the installed library and renders it insecure."
index f88c7b7..8d698ca 100644 (file)
@@ -73,6 +73,13 @@ DBUS_UTIL_arch_sources =                     \
        dbus-sysdeps-util-win.c                 \
        dbus-spawn-win.c
 else
+
+if DBUS_ENABLE_LAUNCHD
+launchd_source = dbus-server-launchd.h dbus-server-launchd.c
+else
+launchd_source =
+endif
+
 DBUS_LIB_arch_sources =                        \
        dbus-uuidgen.c                          \
        dbus-uuidgen.h                          \
@@ -80,6 +87,7 @@ DBUS_LIB_arch_sources =                       \
        dbus-server-unix.h
 
 DBUS_SHARED_arch_sources =                     \
+       $(launchd_source)                       \
        dbus-file-unix.c                        \
        dbus-pipe-unix.c                        \
        dbus-sysdeps-unix.c                     \
index 3e5ad6c..70ad965 100644 (file)
@@ -25,6 +25,7 @@
 #include "dbus-internals.h"
 #include "dbus-server-unix.h"
 #include "dbus-server-socket.h"
+#include "dbus-server-launchd.h"
 #include "dbus-transport-unix.h"
 #include "dbus-connection-internal.h"
 #include "dbus-sysdeps-unix.h"
@@ -178,7 +179,30 @@ _dbus_server_listen_platform_specific (DBusAddressEntry *entry,
       dbus_free (fds);
 
       return DBUS_SERVER_LISTEN_OK;
+       }
+#ifdef DBUS_ENABLE_LAUNCHD
+  else if (strcmp (method, "launchd") == 0)
+    {
+      const char *launchd_env_var = dbus_address_entry_get_value (entry, "env");
+      if (launchd_env_var == NULL)
+        {
+          _dbus_set_bad_address (error, "launchd", "env", NULL);
+          return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
+        }
+      *server_p = _dbus_server_new_for_launchd (launchd_env_var, 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
index 807d2cf..d7022b0 100644 (file)
@@ -81,6 +81,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_socket (DBusString *socket_path,
+                                         const char *launchd_env_var,
+                                         DBusError  *error);
+
 /** Information about a UNIX user */
 typedef struct DBusUserInfo  DBusUserInfo;
 /** Information about a UNIX group */
index 6a713d1..a47756f 100644 (file)
@@ -170,6 +170,59 @@ _dbus_transport_open_platform_specific (DBusAddressEntry  *entry,
           return DBUS_TRANSPORT_OPEN_OK;
         }      
     }
+#ifdef DBUS_ENABLE_LAUNCHD
+  else if (strcmp (method, "launchd") == 0)
+    {
+      DBusError tmp_error = DBUS_ERROR_INIT;
+      const char *launchd_env_var = dbus_address_entry_get_value (entry, "env");
+      const char *launchd_socket;
+      DBusString socket_path;
+      dbus_bool_t valid_socket;
+
+      if (!_dbus_string_init (&socket_path))
+        {
+          _DBUS_SET_OOM (error);
+          return FALSE;
+        }
+
+      if (launchd_env_var == NULL)
+        {
+          _dbus_set_bad_address (error, "launchd", "env", NULL);
+          return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
+        }
+
+      valid_socket = _dbus_lookup_launchd_socket (&socket_path, launchd_env_var, error);
+
+      if (dbus_error_is_set(error))
+        {
+          _dbus_string_free(&socket_path);
+          return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
+        }
+
+      if (!valid_socket)
+        {
+          dbus_set_error(&tmp_error, DBUS_ERROR_BAD_ADDRESS,
+                         "launchd's env var %s does not exist", launchd_env_var);
+          dbus_error_free(error);
+          dbus_move_error(&tmp_error, error);
+          return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
+        }
+
+      launchd_socket = _dbus_string_get_const_data(&socket_path);
+      *transport_p = _dbus_transport_new_for_domain_socket (launchd_socket, FALSE, error);
+
+      if (*transport_p == NULL)
+        {
+          _DBUS_ASSERT_ERROR_IS_SET (error);
+          return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
+        }
+      else
+        {
+          _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+          return DBUS_TRANSPORT_OPEN_OK;
+        }
+    }
+#endif
   else
     {
       _DBUS_ASSERT_ERROR_IS_CLEAR (error);