1/* dbus-server-launchd.c Server methods for interacting with launchd. 2 * Copyright (C) 2007, Tanner Lovelace <lovelace@wayfarer.org> 3 * Copyright (C) 2008, Colin Walters <walters@verbum.org> 4 * Copyright (C) 2008-2009, Benjamin Reed <rangerrick@befunk.com> 5 * Copyright (C) 2009, Jonas B��hr <jonas.baehr@web.de> 6 * 7 * Permission is hereby granted, free of charge, to any person 8 * obtaining a copy of this software and associated documentation 9 * files (the "Software"), to deal in the Software without 10 * restriction, including without limitation the rights to use, copy, 11 * modify, merge, publish, distribute, sublicense, and/or sell copies 12 * of the Software, and to permit persons to whom the Software is 13 * furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be 16 * included in all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 22 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 * DEALINGS IN THE SOFTWARE. 26 */ 27 28#include <config.h> 29#include "dbus-server-launchd.h" 30 31/** 32 * @defgroup DBusServerLaunchd DBusServer implementations for Launchd 33 * @ingroup DBusInternals 34 * @brief Implementation details of DBusServer with Launchd support 35 * 36 * @{ 37 */ 38 39#ifdef DBUS_ENABLE_LAUNCHD 40#include <launch.h> 41#include <errno.h> 42 43#include "dbus-server-socket.h" 44 45/* put other private launchd functions here */ 46 47#endif /* DBUS_ENABLE_LAUNCHD */ 48 49/** 50 * @brief Creates a new server from launchd. 51 * 52 * launchd has allocaed a socket for us. We now query launchd for the 53 * file descriptor of this socket and create a server on it. 54 * In addition we inherit launchd's environment which holds a variable 55 * containing the path to the socket. This is used to init the server's 56 * address which is passed to autolaunched services. 57 * 58 * @param launchd_env_var the environment variable which holds the unix path to the socket 59 * @param error location to store reason for failure. 60 * @returns the new server, or #NULL on failure. 61 */ 62 63DBusServer * 64_dbus_server_new_for_launchd (const char *launchd_env_var, DBusError * error) 65 { 66#ifdef DBUS_ENABLE_LAUNCHD 67 DBusServer *server; 68 DBusString address; 69 int launchd_fd; 70 launch_data_t sockets_dict, checkin_response; 71 launch_data_t checkin_request; 72 launch_data_t listening_fd_array, listening_fd; 73 launch_data_t environment_dict, environment_param; 74 const char *launchd_socket_path, *display; 75 76 launchd_socket_path = _dbus_getenv (launchd_env_var); 77 display = _dbus_getenv ("DISPLAY"); 78 79 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 80 81 if (launchd_socket_path == NULL || *launchd_socket_path == '\0') 82 { 83 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, 84 "launchd's environment variable %s is empty, but should contain a socket path.\n", launchd_env_var); 85 return NULL; 86 } 87 88 if (!_dbus_string_init (&address)) 89 { 90 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 91 return NULL; 92 } 93 if (!_dbus_string_append (&address, "unix:path=")) 94 { 95 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 96 goto l_failed_0; 97 } 98 if (!_dbus_string_append (&address, launchd_socket_path)) 99 { 100 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 101 goto l_failed_0; 102 } 103 104 if ((checkin_request = launch_data_new_string (LAUNCH_KEY_CHECKIN)) == NULL) 105 { 106 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, 107 "launch_data_new_string(\"%s\") Unable to create string.\n", 108 LAUNCH_KEY_CHECKIN); 109 goto l_failed_0; 110 } 111 112 if ((checkin_response = launch_msg (checkin_request)) == NULL) 113 { 114 dbus_set_error (error, DBUS_ERROR_IO_ERROR, 115 "launch_msg(\"%s\") IPC failure: %s\n", 116 LAUNCH_KEY_CHECKIN, strerror (errno)); 117 goto l_failed_0; 118 } 119 120 if (LAUNCH_DATA_ERRNO == launch_data_get_type (checkin_response)) 121 { 122 dbus_set_error (error, DBUS_ERROR_FAILED, "Check-in failed: %s\n", 123 strerror (launch_data_get_errno (checkin_response))); 124 goto l_failed_0; 125 } 126 127 sockets_dict = 128 launch_data_dict_lookup (checkin_response, LAUNCH_JOBKEY_SOCKETS); 129 if (NULL == sockets_dict) 130 { 131 dbus_set_error (error, DBUS_ERROR_IO_ERROR, 132 "No sockets found to answer requests on!\n"); 133 goto l_failed_0; 134 } 135 136 listening_fd_array = 137 launch_data_dict_lookup (sockets_dict, "unix_domain_listener"); 138 if (NULL == listening_fd_array) 139 { 140 dbus_set_error (error, DBUS_ERROR_IO_ERROR, 141 "No known sockets found to answer requests on!\n"); 142 goto l_failed_0; 143 } 144 145 if (launch_data_array_get_count (listening_fd_array) != 1) 146 { 147 dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, 148 "Expected 1 socket from launchd, got %d.\n", 149 launch_data_array_get_count (listening_fd_array)); 150 goto l_failed_0; 151 } 152 153 listening_fd = launch_data_array_get_index (listening_fd_array, 0); 154 launchd_fd = launch_data_get_fd (listening_fd); 155 156 _dbus_fd_set_close_on_exec (launchd_fd); 157 158 if (launchd_fd < 0) 159 { 160 _DBUS_ASSERT_ERROR_IS_SET (error); 161 goto l_failed_0; 162 if (display == NULL || *display == '\0') 163 { 164 environment_dict = launch_data_dict_lookup (checkin_response, LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES); 165 if (NULL == environment_dict) 166 { 167 _dbus_warn ("Unable to retrieve user environment from launchd."); 168 } 169 else 170 { 171 environment_param = launch_data_dict_lookup (environment_dict, "DISPLAY"); 172 if (NULL == environment_param) 173 { 174 _dbus_warn ("Unable to retrieve DISPLAY from launchd."); 175 } 176 else 177 { 178 display = launch_data_get_string(environment_param); 179 _dbus_setenv ("DISPLAY", display); 180 } 181 } 182 } 183 184 } 185 186 server = _dbus_server_new_for_socket (&launchd_fd, 1, &address, 0); 187 if (server == NULL) 188 { 189 dbus_set_error (error, DBUS_ERROR_NO_SERVER, 190 "Unable to listen on launchd fd %d.", launchd_fd); 191 goto l_failed_0; 192 } 193 194 _dbus_string_free (&address); 195 196 return server; 197 198 l_failed_0: 199 _dbus_string_free (&address); 200 201 return NULL; 202#else /* DBUS_ENABLE_LAUNCHD */ 203 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, 204 "address type 'launchd' requested, but launchd support not compiled in"); 205 return NULL; 206#endif 207 } 208 209/** @} */ 210