From fe2b03d47790a62bd179e2d443eda194a4f8e4d6 Mon Sep 17 00:00:00 2001 From: Benjamin Reed Date: Sun, 19 Jul 2009 11:44:50 -0400 Subject: [PATCH 2/7] add launchd implementation --- dbus/dbus-server-launchd.c | 186 ++++++++++++++++++++++++++++++++++++++++++++ dbus/dbus-server-launchd.h | 35 ++++++++ dbus/dbus-sysdeps-unix.c | 101 ++++++++++++++++++++++++ 3 files changed, 322 insertions(+), 0 deletions(-) create mode 100644 dbus/dbus-server-launchd.c create mode 100644 dbus/dbus-server-launchd.h diff --git a/dbus/dbus-server-launchd.c b/dbus/dbus-server-launchd.c new file mode 100644 index 0000000..bcfb558 --- /dev/null +++ b/dbus/dbus-server-launchd.c @@ -0,0 +1,186 @@ +/* dbus-server-launchd.c Server methods for interacting with launchd. + * Copyright (C) 2007, Tanner Lovelace + * Copyright (C) 2008, Colin Walters + * Copyright (C) 2008-2009, Benjamin Reed + * Copyright (C) 2009, Jonas Bähr + * + * 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 "dbus-server-launchd.h" + +/** + * @defgroup DBusServerLaunchd DBusServer implementations for Launchd + * @ingroup DBusInternals + * @brief Implementation details of DBusServer with Launchd support + * + * @{ + */ + +#ifdef DBUS_ENABLE_LAUNCHD +#include +#include + +#include "dbus-server-socket.h" + +/* put other private launchd functions here */ + +#endif /* DBUS_ENABLE_LAUNCHD */ + +/** + * @brief Creates a new server from launchd. + * + * launchd has allocaed a socket for us. We now query launchd for the + * file descriptor of this socket and create a server on it. + * In addition we inherit launchd's environment which holds a variable + * containing the path to the socket. This is used to init the server's + * address which is passed to autolaunched services. + * + * @param launchd_env_var the environment variable which holds the unix path to the socket + * @param error location to store reason for failure. + * @returns the new server, or #NULL on failure. + */ + +DBusServer * +_dbus_server_new_for_launchd (const char *launchd_env_var, DBusError * error) + { +#ifdef DBUS_ENABLE_LAUNCHD + 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; + launch_data_t environment_dict, environment_param; + const char *launchd_socket_path; + + launchd_socket_path = _dbus_getenv (launchd_env_var); + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (launchd_socket_path == NULL || *launchd_socket_path == '\0') + { + dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, + "launchd's environment variable %s is empty, but should contain a socket path.\n", launchd_env_var); + return NULL; + } + + if (!_dbus_string_init (&address)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } + if (!_dbus_string_append (&address, "unix:path=")) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto l_failed_0; + } + if (!_dbus_string_append (&address, launchd_socket_path)) + { + 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, "unix_domain_listener"); + 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; +#else /* DBUS_ENABLE_LAUNCHD */ + dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, + "address type 'launchd' requested, but launchd support not compiled in"); + return NULL; +#endif + } + +/** @} */ diff --git a/dbus/dbus-server-launchd.h b/dbus/dbus-server-launchd.h new file mode 100644 index 0000000..ec5cbac --- /dev/null +++ b/dbus/dbus-server-launchd.h @@ -0,0 +1,35 @@ +/* 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 (const char *launchd_env_var, DBusError * error); + +DBUS_END_DECLS +#endif /* DBUS_SERVER_LAUNCHD_H */ diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c index f0f1e70..d2559f2 100644 --- a/dbus/dbus-sysdeps-unix.c +++ b/dbus/dbus-sysdeps-unix.c @@ -3568,6 +3568,102 @@ _dbus_read_local_machine_uuid (DBusGUID *machine_id, #define DBUS_UNIX_STANDARD_SYSTEM_SERVICEDIR "/dbus-1/system-services" /** + * quries launchd for a specific env var which holds the socket path. + * @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 + */ +dbus_bool_t +_dbus_lookup_launchd_socket (DBusString *socket_path, + const char *launchd_env_var, + DBusError *error) +{ +#ifdef DBUS_ENABLE_LAUNCHD + char *argv[4]; + int i; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + i = 0; + argv[i] = "launchctl"; + ++i; + argv[i] = "getenv"; + ++i; + argv[i] = (char*)launchd_env_var; + ++i; + argv[i] = NULL; + ++i; + + _dbus_assert (i == _DBUS_N_ELEMENTS (argv)); + + if (!_read_subprocess_line_argv(argv[0], TRUE, argv, socket_path, error)) + { + return FALSE; + } + + /* no error, but no result either */ + if (_dbus_string_get_length(socket_path) == 0) + { + return FALSE; + } + + /* strip the carriage-return */ + _dbus_string_shorten(socket_path, 1); + return TRUE; +#else /* DBUS_ENABLE_LAUNCHD */ + dbus_set_error(error, DBUS_ERROR_NOT_SUPPORTED, + "can't lookup socket from launchd; launchd support not compiled in"); + return FALSE; +#endif +} + +static dbus_bool_t +_dbus_lookup_session_address_launchd (DBusString *address, DBusError *error) +{ + dbus_bool_t valid_socket; + DBusString *socket_path; + + if (!_dbus_string_init (socket_path)) + { + _DBUS_SET_OOM (error); + return FALSE; + } + + valid_socket = _dbus_lookup_launchd_socket (socket_path, "DBUS_LAUNCHD_SESSION_BUS_SOCKET", error); + + if (dbus_error_is_set(error)) + { + _dbus_string_free(socket_path); + return FALSE; + } + + if (!valid_socket) + { + dbus_set_error(error, "no socket path", + "launchd did not provide a socket path, " + "verify that org.freedesktop.dbus-session.plist is loaded!"); + _dbus_string_free(socket_path); + return FALSE; + } + if (!_dbus_string_append (address, "unix:path=")) + { + _DBUS_SET_OOM (error); + _dbus_string_free(socket_path); + return FALSE; + } + if (!_dbus_string_copy (socket_path, 0, address, + _dbus_string_get_length (address))) + { + _DBUS_SET_OOM (error); + _dbus_string_free(socket_path); + return FALSE; + } + + _dbus_string_free(socket_path); + return TRUE; +} + +/** * Determines the address of the session bus by querying a * platform-specific method. * @@ -3591,12 +3687,17 @@ _dbus_lookup_session_address (dbus_bool_t *supported, DBusString *address, DBusError *error) { +#ifdef DBUS_ENABLE_LAUNCHD + *supported = TRUE; + return _dbus_lookup_session_address_launchd (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 } /** -- 1.6.3.2