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