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