2 * Copyright © 2011 Intel Corporation
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.
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.
28 #include <sys/socket.h>
36 #include "xserver-server-protocol.h"
40 weston_xserver_handle_event(int listen_fd, uint32_t mask, void *data)
42 struct weston_xserver *wxs = data;
43 char display[8], s[8];
46 struct weston_config_section *section;
48 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
49 weston_log("socketpair failed\n");
53 wxs->process.pid = fork();
54 switch (wxs->process.pid) {
56 /* SOCK_CLOEXEC closes both ends, so we need to unset
57 * the flag on the client fd. */
58 client_fd = dup(sv[1]);
62 snprintf(s, sizeof s, "%d", client_fd);
63 setenv("WAYLAND_SOCKET", s, 1);
65 snprintf(display, sizeof display, ":%d", wxs->display);
67 section = weston_config_get_section(wxs->compositor->config, "xwayland", NULL, NULL);
68 weston_config_section_get_string(section, "path", &xserver, XSERVER_PATH);
79 weston_log("exec failed: %m\n");
84 weston_log("forked X server, pid %d\n", wxs->process.pid);
87 wxs->client = wl_client_create(wxs->wl_display, sv[0]);
89 weston_watch_process(&wxs->process);
91 wl_event_source_remove(wxs->abstract_source);
92 wl_event_source_remove(wxs->unix_source);
96 weston_log( "failed to fork\n");
104 weston_xserver_shutdown(struct weston_xserver *wxs)
108 snprintf(path, sizeof path, "/tmp/.X%d-lock", wxs->display);
110 snprintf(path, sizeof path, "/tmp/.X11-unix/X%d", wxs->display);
112 if (wxs->process.pid == 0) {
113 wl_event_source_remove(wxs->abstract_source);
114 wl_event_source_remove(wxs->unix_source);
116 close(wxs->abstract_fd);
119 weston_wm_destroy(wxs->wm);
124 weston_xserver_cleanup(struct weston_process *process, int status)
126 struct weston_xserver *wxs =
127 container_of(process, struct weston_xserver, process);
129 wxs->process.pid = 0;
131 wxs->resource = NULL;
133 wxs->abstract_source =
134 wl_event_loop_add_fd(wxs->loop, wxs->abstract_fd,
136 weston_xserver_handle_event, wxs);
139 wl_event_loop_add_fd(wxs->loop, wxs->unix_fd,
141 weston_xserver_handle_event, wxs);
144 weston_log("xserver exited, code %d\n", status);
145 weston_wm_destroy(wxs->wm);
148 /* If the X server crashes before it binds to the
149 * xserver interface, shut down and don't try
151 weston_log("xserver crashing too fast: %d\n", status);
152 weston_xserver_shutdown(wxs);
157 bind_xserver(struct wl_client *client,
158 void *data, uint32_t version, uint32_t id)
160 struct weston_xserver *wxs = data;
162 /* If it's a different client than the xserver we launched,
163 * don't start the wm. */
164 if (client != wxs->client)
168 wl_resource_create(client, &xserver_interface,
170 wl_resource_set_implementation(wxs->resource, &xserver_implementation,
173 wxs->wm = weston_wm_create(wxs);
174 if (wxs->wm == NULL) {
175 weston_log("failed to create wm\n");
178 xserver_send_listen_socket(wxs->resource, wxs->abstract_fd);
179 xserver_send_listen_socket(wxs->resource, wxs->unix_fd);
183 bind_to_abstract_socket(int display)
185 struct sockaddr_un addr;
186 socklen_t size, name_size;
189 fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
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));
204 if (listen(fd, 1) < 0) {
213 bind_to_unix_socket(int display)
215 struct sockaddr_un addr;
216 socklen_t size, name_size;
219 fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
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));
235 if (listen(fd, 1) < 0) {
236 unlink(addr.sun_path);
245 create_lockfile(int display, char *lockfile, size_t lsize)
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));
265 other = strtol(pid, &end, 0);
266 if (end != pid + 10) {
267 weston_log("can't parse lock file %s\n",
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);
278 if (unlink(lockfile))
279 /* If we fail to unlink, return EEXIST
280 so we try the next display number.*/
291 weston_log("failed to create lock file %s: %s\n",
292 lockfile, strerror(errno));
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) {
311 weston_xserver_destroy(struct wl_listener *l, void *data)
313 struct weston_xserver *wxs =
314 container_of(l, struct weston_xserver, destroy_listener);
320 weston_xserver_shutdown(wxs);
326 module_init(struct weston_compositor *compositor,
327 int *argc, char *argv[])
330 struct wl_display *display = compositor->wl_display;
331 struct weston_xserver *wxs;
332 char lockfile[256], display_name[8];
334 wxs = zalloc(sizeof *wxs);
335 wxs->process.cleanup = weston_xserver_cleanup;
336 wxs->wl_display = display;
337 wxs->compositor = compositor;
342 if (create_lockfile(wxs->display, lockfile, sizeof lockfile) < 0) {
343 if (errno == EAGAIN) {
345 } else if (errno == EEXIST) {
354 wxs->abstract_fd = bind_to_abstract_socket(wxs->display);
355 if (wxs->abstract_fd < 0 && errno == EADDRINUSE) {
361 wxs->unix_fd = bind_to_unix_socket(wxs->display);
362 if (wxs->unix_fd < 0) {
364 close(wxs->abstract_fd);
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);
373 wxs->loop = wl_display_get_event_loop(display);
374 wxs->abstract_source =
375 wl_event_loop_add_fd(wxs->loop, wxs->abstract_fd,
377 weston_xserver_handle_event, wxs);
379 wl_event_loop_add_fd(wxs->loop, wxs->unix_fd,
381 weston_xserver_handle_event, wxs);
383 wl_global_create(display, &xserver_interface, 1, wxs, bind_xserver);
385 wxs->destroy_listener.notify = weston_xserver_destroy;
386 wl_signal_add(&compositor->destroy_signal, &wxs->destroy_listener);