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-misc.h"
44 #include "dbus-server-socket.h"
45 #include "dbus-sysdeps-unix.h"
46
47 /* put other private launchd functions here */
48
49 #endif /* DBUS_ENABLE_LAUNCHD */
50
51 /**
52 * @brief Creates a new server from launchd.
53 *
54 * launchd has allocaed a socket for us. We now query launchd for the
55 * file descriptor of this socket and create a server on it.
56 * In addition we inherit launchd's environment which holds a variable
57 * containing the path to the socket. This is used to init the server's
58 * address which is passed to autolaunched services.
59 *
60 * @param launchd_env_var the environment variable which holds the unix path to the socket
61 * @param error location to store reason for failure.
62 * @returns the new server, or #NULL on failure.
63 */
64
65 DBusServer *
_dbus_server_new_for_launchd(const char * launchd_env_var,DBusError * error)66 _dbus_server_new_for_launchd (const char *launchd_env_var, DBusError * error)
67 {
68 #ifdef DBUS_ENABLE_LAUNCHD
69 DBusServer *server;
70 DBusString address;
71 int launchd_fd;
72 launch_data_t sockets_dict, checkin_response;
73 launch_data_t checkin_request;
74 launch_data_t listening_fd_array, listening_fd;
75 launch_data_t environment_dict, environment_param;
76 const char *launchd_socket_path, *display;
77
78 launchd_socket_path = _dbus_getenv (launchd_env_var);
79 display = _dbus_getenv ("DISPLAY");
80
81 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
82
83 if (launchd_socket_path == NULL || *launchd_socket_path == '\0')
84 {
85 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
86 "launchd's environment variable %s is empty, but should contain a socket path.\n", launchd_env_var);
87 return NULL;
88 }
89
90 if (!_dbus_string_init (&address))
91 {
92 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
93 return NULL;
94 }
95 if (!_dbus_string_append (&address, "unix:path="))
96 {
97 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
98 goto l_failed_0;
99 }
100 if (!_dbus_string_append (&address, launchd_socket_path))
101 {
102 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
103 goto l_failed_0;
104 }
105
106 if ((checkin_request = launch_data_new_string (LAUNCH_KEY_CHECKIN)) == NULL)
107 {
108 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
109 "launch_data_new_string(\"%s\") Unable to create string.\n",
110 LAUNCH_KEY_CHECKIN);
111 goto l_failed_0;
112 }
113
114 if ((checkin_response = launch_msg (checkin_request)) == NULL)
115 {
116 dbus_set_error (error, DBUS_ERROR_IO_ERROR,
117 "launch_msg(\"%s\") IPC failure: %s\n",
118 LAUNCH_KEY_CHECKIN, strerror (errno));
119 goto l_failed_0;
120 }
121
122 if (LAUNCH_DATA_ERRNO == launch_data_get_type (checkin_response))
123 {
124 dbus_set_error (error, DBUS_ERROR_FAILED, "Check-in failed: %s\n",
125 strerror (launch_data_get_errno (checkin_response)));
126 goto l_failed_0;
127 }
128
129 sockets_dict =
130 launch_data_dict_lookup (checkin_response, LAUNCH_JOBKEY_SOCKETS);
131 if (NULL == sockets_dict)
132 {
133 dbus_set_error (error, DBUS_ERROR_IO_ERROR,
134 "No sockets found to answer requests on!\n");
135 goto l_failed_0;
136 }
137
138 listening_fd_array =
139 launch_data_dict_lookup (sockets_dict, "unix_domain_listener");
140 if (NULL == listening_fd_array)
141 {
142 dbus_set_error (error, DBUS_ERROR_IO_ERROR,
143 "No known sockets found to answer requests on!\n");
144 goto l_failed_0;
145 }
146
147 if (launch_data_array_get_count (listening_fd_array) != 1)
148 {
149 dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
150 "Expected 1 socket from launchd, got %d.\n",
151 launch_data_array_get_count (listening_fd_array));
152 goto l_failed_0;
153 }
154
155 listening_fd = launch_data_array_get_index (listening_fd_array, 0);
156 launchd_fd = launch_data_get_fd (listening_fd);
157
158 _dbus_fd_set_close_on_exec (launchd_fd);
159
160 if (launchd_fd < 0)
161 {
162 _DBUS_ASSERT_ERROR_IS_SET (error);
163 goto l_failed_0;
164 if (display == NULL || *display == '\0')
165 {
166 environment_dict = launch_data_dict_lookup (checkin_response, LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES);
167 if (NULL == environment_dict)
168 {
169 _dbus_warn ("Unable to retrieve user environment from launchd.");
170 }
171 else
172 {
173 environment_param = launch_data_dict_lookup (environment_dict, "DISPLAY");
174 if (NULL == environment_param)
175 {
176 _dbus_warn ("Unable to retrieve DISPLAY from launchd.");
177 }
178 else
179 {
180 display = launch_data_get_string(environment_param);
181 dbus_setenv ("DISPLAY", display);
182 }
183 }
184 }
185
186 }
187
188 server = _dbus_server_new_for_socket (&launchd_fd, 1, &address, 0, error);
189 if (server == NULL)
190 {
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