D-Bus  1.8.20
dbus-server-launchd.c
00001 /* dbus-server-launchd.c Server methods for interacting with launchd.
00002  * Copyright (C) 2007, Tanner Lovelace <lovelace@wayfarer.org>
00003  * Copyright (C) 2008, Colin Walters <walters@verbum.org>
00004  * Copyright (C) 2008-2009, Benjamin Reed <rangerrick@befunk.com>
00005  * Copyright (C) 2009, Jonas Bähr <jonas.baehr@web.de>
00006  *
00007  * Permission is hereby granted, free of charge, to any person
00008  * obtaining a copy of this software and associated documentation
00009  * files (the "Software"), to deal in the Software without
00010  * restriction, including without limitation the rights to use, copy,
00011  * modify, merge, publish, distribute, sublicense, and/or sell copies
00012  * of the Software, and to permit persons to whom the Software is
00013  * furnished to do so, subject to the following conditions:
00014  *
00015  * The above copyright notice and this permission notice shall be
00016  * included in all copies or substantial portions of the Software.
00017  *
00018  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00019  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00020  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00021  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
00022  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
00023  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00024  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00025  * DEALINGS IN THE SOFTWARE.
00026  */
00027 
00028 #include <config.h>
00029 #include "dbus-server-launchd.h"
00030 
00039 #ifdef DBUS_ENABLE_LAUNCHD
00040 #include <launch.h>
00041 #include <errno.h>
00042 
00043 #include "dbus-misc.h"
00044 #include "dbus-server-socket.h"
00045 
00046 /* put other private launchd functions here */
00047 
00048 #endif /* DBUS_ENABLE_LAUNCHD */
00049 
00064 DBusServer *
00065 _dbus_server_new_for_launchd (const char *launchd_env_var, DBusError * error)
00066   {
00067 #ifdef DBUS_ENABLE_LAUNCHD
00068     DBusServer *server;
00069     DBusString address;
00070     int launchd_fd;
00071     launch_data_t sockets_dict, checkin_response;
00072     launch_data_t checkin_request;
00073     launch_data_t listening_fd_array, listening_fd;
00074     launch_data_t environment_dict, environment_param;
00075     const char *launchd_socket_path, *display;
00076 
00077     launchd_socket_path = _dbus_getenv (launchd_env_var);
00078     display = _dbus_getenv ("DISPLAY");
00079 
00080     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00081 
00082     if (launchd_socket_path == NULL || *launchd_socket_path == '\0')
00083       {
00084         dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
00085                         "launchd's environment variable %s is empty, but should contain a socket path.\n", launchd_env_var);
00086         return NULL;
00087       }
00088 
00089     if (!_dbus_string_init (&address))
00090       {
00091         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00092         return NULL;
00093       }
00094     if (!_dbus_string_append (&address, "unix:path="))
00095       {
00096         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00097         goto l_failed_0;
00098       }
00099     if (!_dbus_string_append (&address, launchd_socket_path))
00100       {
00101         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00102         goto l_failed_0;
00103       }
00104 
00105     if ((checkin_request = launch_data_new_string (LAUNCH_KEY_CHECKIN)) == NULL)
00106       {
00107         dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00108                         "launch_data_new_string(\"%s\") Unable to create string.\n",
00109                         LAUNCH_KEY_CHECKIN);
00110         goto l_failed_0;
00111       }
00112 
00113     if ((checkin_response = launch_msg (checkin_request)) == NULL)
00114       {
00115         dbus_set_error (error, DBUS_ERROR_IO_ERROR,
00116                         "launch_msg(\"%s\") IPC failure: %s\n",
00117                         LAUNCH_KEY_CHECKIN, strerror (errno));
00118         goto l_failed_0;
00119       }
00120 
00121     if (LAUNCH_DATA_ERRNO == launch_data_get_type (checkin_response))
00122       {
00123         dbus_set_error (error, DBUS_ERROR_FAILED, "Check-in failed: %s\n",
00124                         strerror (launch_data_get_errno (checkin_response)));
00125         goto l_failed_0;
00126       }
00127 
00128     sockets_dict =
00129       launch_data_dict_lookup (checkin_response, LAUNCH_JOBKEY_SOCKETS);
00130     if (NULL == sockets_dict)
00131       {
00132         dbus_set_error (error, DBUS_ERROR_IO_ERROR,
00133                         "No sockets found to answer requests on!\n");
00134         goto l_failed_0;
00135       }
00136 
00137     listening_fd_array =
00138       launch_data_dict_lookup (sockets_dict, "unix_domain_listener");
00139     if (NULL == listening_fd_array)
00140       {
00141         dbus_set_error (error, DBUS_ERROR_IO_ERROR,
00142                         "No known sockets found to answer requests on!\n");
00143         goto l_failed_0;
00144       }
00145 
00146     if (launch_data_array_get_count (listening_fd_array) != 1)
00147       {
00148         dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
00149                         "Expected 1 socket from launchd, got %d.\n",
00150                         launch_data_array_get_count (listening_fd_array));
00151         goto l_failed_0;
00152       }
00153 
00154     listening_fd = launch_data_array_get_index (listening_fd_array, 0);
00155     launchd_fd = launch_data_get_fd (listening_fd);
00156 
00157     _dbus_fd_set_close_on_exec (launchd_fd);
00158 
00159     if (launchd_fd < 0)
00160       {
00161         _DBUS_ASSERT_ERROR_IS_SET (error);
00162         goto l_failed_0;
00163   if (display == NULL || *display == '\0')
00164     {
00165       environment_dict = launch_data_dict_lookup (checkin_response, LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES);
00166       if (NULL == environment_dict)
00167         {
00168           _dbus_warn ("Unable to retrieve user environment from launchd.");
00169         }
00170       else
00171         {
00172           environment_param = launch_data_dict_lookup (environment_dict, "DISPLAY");
00173           if (NULL == environment_param)
00174             {
00175               _dbus_warn ("Unable to retrieve DISPLAY from launchd.");
00176             }
00177           else
00178             {
00179               display = launch_data_get_string(environment_param);
00180               dbus_setenv ("DISPLAY", display);
00181             }
00182         }
00183     }
00184 
00185       }
00186 
00187     server = _dbus_server_new_for_socket (&launchd_fd, 1, &address, 0);
00188     if (server == NULL)
00189       {
00190         dbus_set_error (error, DBUS_ERROR_NO_SERVER,
00191                         "Unable to listen on launchd fd %d.", launchd_fd);
00192         goto l_failed_0;
00193       }
00194 
00195     _dbus_string_free (&address);
00196 
00197     return server;
00198 
00199   l_failed_0:
00200     _dbus_string_free (&address);
00201 
00202     return NULL;
00203 #else /* DBUS_ENABLE_LAUNCHD */
00204     dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
00205                     "address type 'launchd' requested, but launchd support not compiled in");
00206     return NULL;
00207 #endif
00208   }
00209