xwayland: Use new Xwayland DDX
[profile/ivi/weston-ivi-shell.git] / xwayland / launcher.c
1 /*
2  * Copyright © 2011 Intel Corporation
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and
5  * its documentation for any purpose is hereby granted without fee, provided
6  * that the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation, and that the name of the copyright holders not be used in
9  * advertising or publicity pertaining to distribution of the software
10  * without specific, written prior permission.  The copyright holders make
11  * no representations about the suitability of this software for any
12  * purpose.  It is provided "as is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21  */
22
23 #include "config.h"
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <sys/socket.h>
29 #include <sys/un.h>
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <unistd.h>
33 #include <signal.h>
34
35 #include "xwayland.h"
36 #include "xserver-server-protocol.h"
37
38
39 static int
40 handle_sigusr1(int signal_number, void *data)
41 {
42         struct weston_xserver *wxs = data;
43
44         /* We'd be safer if we actually had the struct
45          * signalfd_siginfo from the signalfd data and could verify
46          * this came from Xwayland.*/
47         weston_wm_create(wxs, wxs->wm_fd);
48         wl_event_source_remove(wxs->sigusr1_source);
49
50         return 1;
51 }
52
53 static int
54 weston_xserver_handle_event(int listen_fd, uint32_t mask, void *data)
55 {
56         struct weston_xserver *wxs = data;
57         char display[8], s[8], abstract_fd[8], unix_fd[8], wm_fd[8];
58         int sv[2], wm[2], fd;
59         char *xserver = NULL;
60         struct weston_config_section *section;
61
62         if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
63                 weston_log("wl connection socketpair failed\n");
64                 return 1;
65         }
66
67         if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, wm) < 0) {
68                 weston_log("X wm connection socketpair failed\n");
69                 return 1;
70         }
71
72         wxs->process.pid = fork();
73         switch (wxs->process.pid) {
74         case 0:
75                 /* SOCK_CLOEXEC closes both ends, so we need to unset
76                  * the flag on the client fd. */
77                 fd = dup(sv[1]);
78                 if (fd < 0)
79                         goto fail;
80                 snprintf(s, sizeof s, "%d", fd);
81                 setenv("WAYLAND_SOCKET", s, 1);
82
83                 snprintf(display, sizeof display, ":%d", wxs->display);
84
85                 fd = dup(wxs->abstract_fd);
86                 if (fd < 0)
87                         goto fail;
88                 snprintf(abstract_fd, sizeof abstract_fd, "%d", fd);
89                 fd = dup(wxs->unix_fd);
90                 if (fd < 0)
91                         goto fail;
92                 snprintf(unix_fd, sizeof unix_fd, "%d", fd);
93                 fd = dup(wm[1]);
94                 if (fd < 0)
95                         goto fail;
96                 snprintf(wm_fd, sizeof wm_fd, "%d", fd);
97
98                 section = weston_config_get_section(wxs->compositor->config,
99                                                     "xwayland", NULL, NULL);
100                 weston_config_section_get_string(section, "path",
101                                                  &xserver, XSERVER_PATH);
102
103                 /* Ignore SIGUSR1 in the child, which will make the X
104                  * server send SIGUSR1 to the parent (weston) when
105                  * it's done with initialization.  During
106                  * initialization the X server will round trip and
107                  * block on the wayland compositor, so avoid making
108                  * blocking requests (like xcb_connect_to_fd) until
109                  * it's done with that. */
110                 signal(SIGUSR1, SIG_IGN);
111
112                 if (execl(xserver,
113                           xserver,
114                           display,
115                           "-rootless",
116                           "-listen", abstract_fd,
117                           "-listen", unix_fd,
118                           "-wm", wm_fd,
119                           "-terminate",
120                           NULL) < 0)
121                         weston_log("exec failed: %m\n");
122         fail:
123                 _exit(EXIT_FAILURE);
124
125         default:
126                 weston_log("forked X server, pid %d\n", wxs->process.pid);
127
128                 close(sv[1]);
129                 wxs->client = wl_client_create(wxs->wl_display, sv[0]);
130
131                 close(wm[1]);
132                 wxs->wm_fd = wm[0];
133
134                 weston_watch_process(&wxs->process);
135
136                 wl_event_source_remove(wxs->abstract_source);
137                 wl_event_source_remove(wxs->unix_source);
138                 break;
139
140         case -1:
141                 weston_log( "failed to fork\n");
142                 break;
143         }
144
145         return 1;
146 }
147
148 static void
149 weston_xserver_shutdown(struct weston_xserver *wxs)
150 {
151         char path[256];
152
153         snprintf(path, sizeof path, "/tmp/.X%d-lock", wxs->display);
154         unlink(path);
155         snprintf(path, sizeof path, "/tmp/.X11-unix/X%d", wxs->display);
156         unlink(path);
157         if (wxs->process.pid == 0) {
158                 wl_event_source_remove(wxs->abstract_source);
159                 wl_event_source_remove(wxs->unix_source);
160         }
161         close(wxs->abstract_fd);
162         close(wxs->unix_fd);
163         if (wxs->wm)
164                 weston_wm_destroy(wxs->wm);
165         wxs->loop = NULL;
166 }
167
168 static void
169 weston_xserver_cleanup(struct weston_process *process, int status)
170 {
171         struct weston_xserver *wxs =
172                 container_of(process, struct weston_xserver, process);
173
174         wxs->process.pid = 0;
175         wxs->client = NULL;
176         wxs->resource = NULL;
177
178         wxs->abstract_source =
179                 wl_event_loop_add_fd(wxs->loop, wxs->abstract_fd,
180                                      WL_EVENT_READABLE,
181                                      weston_xserver_handle_event, wxs);
182
183         wxs->unix_source =
184                 wl_event_loop_add_fd(wxs->loop, wxs->unix_fd,
185                                      WL_EVENT_READABLE,
186                                      weston_xserver_handle_event, wxs);
187
188         if (wxs->wm) {
189                 weston_log("xserver exited, code %d\n", status);
190                 weston_wm_destroy(wxs->wm);
191                 wxs->wm = NULL;
192         } else {
193                 /* If the X server crashes before it binds to the
194                  * xserver interface, shut down and don't try
195                  * again. */
196                 weston_log("xserver crashing too fast: %d\n", status);
197                 weston_xserver_shutdown(wxs);
198         }
199 }
200
201 static int
202 bind_to_abstract_socket(int display)
203 {
204         struct sockaddr_un addr;
205         socklen_t size, name_size;
206         int fd;
207
208         fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
209         if (fd < 0)
210                 return -1;
211
212         addr.sun_family = AF_LOCAL;
213         name_size = snprintf(addr.sun_path, sizeof addr.sun_path,
214                              "%c/tmp/.X11-unix/X%d", 0, display);
215         size = offsetof(struct sockaddr_un, sun_path) + name_size;
216         if (bind(fd, (struct sockaddr *) &addr, size) < 0) {
217                 weston_log("failed to bind to @%s: %s\n",
218                         addr.sun_path + 1, strerror(errno));
219                 close(fd);
220                 return -1;
221         }
222
223         if (listen(fd, 1) < 0) {
224                 close(fd);
225                 return -1;
226         }
227
228         return fd;
229 }
230
231 static int
232 bind_to_unix_socket(int display)
233 {
234         struct sockaddr_un addr;
235         socklen_t size, name_size;
236         int fd;
237
238         fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
239         if (fd < 0)
240                 return -1;
241
242         addr.sun_family = AF_LOCAL;
243         name_size = snprintf(addr.sun_path, sizeof addr.sun_path,
244                              "/tmp/.X11-unix/X%d", display) + 1;
245         size = offsetof(struct sockaddr_un, sun_path) + name_size;
246         unlink(addr.sun_path);
247         if (bind(fd, (struct sockaddr *) &addr, size) < 0) {
248                 weston_log("failed to bind to %s (%s)\n",
249                         addr.sun_path, strerror(errno));
250                 close(fd);
251                 return -1;
252         }
253
254         if (listen(fd, 1) < 0) {
255                 unlink(addr.sun_path);
256                 close(fd);
257                 return -1;
258         }
259
260         return fd;
261 }
262
263 static int
264 create_lockfile(int display, char *lockfile, size_t lsize)
265 {
266         char pid[16], *end;
267         int fd, size;
268         pid_t other;
269
270         snprintf(lockfile, lsize, "/tmp/.X%d-lock", display);
271         fd = open(lockfile, O_WRONLY | O_CLOEXEC | O_CREAT | O_EXCL, 0444);
272         if (fd < 0 && errno == EEXIST) {
273                 fd = open(lockfile, O_CLOEXEC | O_RDONLY);
274                 if (fd < 0 || read(fd, pid, 11) != 11) {
275                         weston_log("can't read lock file %s: %s\n",
276                                 lockfile, strerror(errno));
277                         if (fd >= 0)
278                                 close (fd);
279
280                         errno = EEXIST;
281                         return -1;
282                 }
283
284                 other = strtol(pid, &end, 0);
285                 if (end != pid + 10) {
286                         weston_log("can't parse lock file %s\n",
287                                 lockfile);
288                         close(fd);
289                         errno = EEXIST;
290                         return -1;
291                 }
292
293                 if (kill(other, 0) < 0 && errno == ESRCH) {
294                         /* stale lock file; unlink and try again */
295                         weston_log("unlinking stale lock file %s\n", lockfile);
296                         close(fd);
297                         if (unlink(lockfile))
298                                 /* If we fail to unlink, return EEXIST
299                                    so we try the next display number.*/
300                                 errno = EEXIST;
301                         else
302                                 errno = EAGAIN;
303                         return -1;
304                 }
305
306                 close(fd);
307                 errno = EEXIST;
308                 return -1;
309         } else if (fd < 0) {
310                 weston_log("failed to create lock file %s: %s\n",
311                         lockfile, strerror(errno));
312                 return -1;
313         }
314
315         /* Subtle detail: we use the pid of the wayland
316          * compositor, not the xserver in the lock file. */
317         size = snprintf(pid, sizeof pid, "%10d\n", getpid());
318         if (write(fd, pid, size) != size) {
319                 unlink(lockfile);
320                 close(fd);
321                 return -1;
322         }
323
324         close(fd);
325
326         return 0;
327 }
328
329 static void
330 weston_xserver_destroy(struct wl_listener *l, void *data)
331 {
332         struct weston_xserver *wxs =
333                 container_of(l, struct weston_xserver, destroy_listener);
334
335         if (!wxs)
336                 return;
337
338         if (wxs->loop)
339                 weston_xserver_shutdown(wxs);
340
341         free(wxs);
342 }
343
344 WL_EXPORT int
345 module_init(struct weston_compositor *compositor,
346             int *argc, char *argv[])
347
348 {
349         struct wl_display *display = compositor->wl_display;
350         struct weston_xserver *wxs;
351         char lockfile[256], display_name[8];
352
353         wxs = zalloc(sizeof *wxs);
354         wxs->process.cleanup = weston_xserver_cleanup;
355         wxs->wl_display = display;
356         wxs->compositor = compositor;
357
358         wxs->display = 0;
359
360  retry:
361         if (create_lockfile(wxs->display, lockfile, sizeof lockfile) < 0) {
362                 if (errno == EAGAIN) {
363                         goto retry;
364                 } else if (errno == EEXIST) {
365                         wxs->display++;
366                         goto retry;
367                 } else {
368                         free(wxs);
369                         return -1;
370                 }
371         }
372
373         wxs->abstract_fd = bind_to_abstract_socket(wxs->display);
374         if (wxs->abstract_fd < 0 && errno == EADDRINUSE) {
375                 wxs->display++;
376                 unlink(lockfile);
377                 goto retry;
378         }
379
380         wxs->unix_fd = bind_to_unix_socket(wxs->display);
381         if (wxs->unix_fd < 0) {
382                 unlink(lockfile);
383                 close(wxs->abstract_fd);
384                 free(wxs);
385                 return -1;
386         }
387
388         snprintf(display_name, sizeof display_name, ":%d", wxs->display);
389         weston_log("xserver listening on display %s\n", display_name);
390         setenv("DISPLAY", display_name, 1);
391
392         wxs->loop = wl_display_get_event_loop(display);
393         wxs->abstract_source =
394                 wl_event_loop_add_fd(wxs->loop, wxs->abstract_fd,
395                                      WL_EVENT_READABLE,
396                                      weston_xserver_handle_event, wxs);
397         wxs->unix_source =
398                 wl_event_loop_add_fd(wxs->loop, wxs->unix_fd,
399                                      WL_EVENT_READABLE,
400                                      weston_xserver_handle_event, wxs);
401
402         wxs->sigusr1_source = wl_event_loop_add_signal(wxs->loop, SIGUSR1,
403                                                        handle_sigusr1, wxs);
404         wxs->destroy_listener.notify = weston_xserver_destroy;
405         wl_signal_add(&compositor->destroy_signal, &wxs->destroy_listener);
406
407         return 0;
408 }