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