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"
41 weston_xserver_handle_event(int listen_fd, uint32_t mask, void *data)
43 struct weston_xserver *mxs = data;
44 char display[8], s[8];
47 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
48 weston_log("socketpair failed\n");
52 mxs->process.pid = fork();
53 switch (mxs->process.pid) {
55 /* SOCK_CLOEXEC closes both ends, so we need to unset
56 * the flag on the client fd. */
57 client_fd = dup(sv[1]);
61 snprintf(s, sizeof s, "%d", client_fd);
62 setenv("WAYLAND_SOCKET", s, 1);
64 snprintf(display, sizeof display, ":%d", mxs->display);
66 if (execl(XSERVER_PATH,
75 weston_log("exec failed: %m\n");
79 weston_log("forked X server, pid %d\n", mxs->process.pid);
82 mxs->client = wl_client_create(mxs->wl_display, sv[0]);
84 weston_watch_process(&mxs->process);
86 wl_event_source_remove(mxs->abstract_source);
87 wl_event_source_remove(mxs->unix_source);
91 weston_log( "failed to fork\n");
99 weston_xserver_shutdown(struct weston_xserver *wxs)
103 snprintf(path, sizeof path, "/tmp/.X%d-lock", wxs->display);
105 snprintf(path, sizeof path, "/tmp/.X11-unix/X%d", wxs->display);
107 if (wxs->process.pid == 0) {
108 wl_event_source_remove(wxs->abstract_source);
109 wl_event_source_remove(wxs->unix_source);
111 close(wxs->abstract_fd);
114 weston_wm_destroy(wxs->wm);
119 weston_xserver_cleanup(struct weston_process *process, int status)
121 struct weston_xserver *mxs =
122 container_of(process, struct weston_xserver, process);
124 mxs->process.pid = 0;
126 mxs->resource = NULL;
128 mxs->abstract_source =
129 wl_event_loop_add_fd(mxs->loop, mxs->abstract_fd,
131 weston_xserver_handle_event, mxs);
134 wl_event_loop_add_fd(mxs->loop, mxs->unix_fd,
136 weston_xserver_handle_event, mxs);
139 weston_log("xserver exited, code %d\n", status);
140 weston_wm_destroy(mxs->wm);
143 /* If the X server crashes before it binds to the
144 * xserver interface, shut down and don't try
146 weston_log("xserver crashing too fast: %d\n", status);
147 weston_xserver_shutdown(mxs);
152 bind_xserver(struct wl_client *client,
153 void *data, uint32_t version, uint32_t id)
155 struct weston_xserver *wxs = data;
157 /* If it's a different client than the xserver we launched,
158 * don't start the wm. */
159 if (client != wxs->client)
163 wl_client_add_object(client, &xserver_interface,
164 &xserver_implementation, id, wxs);
166 wxs->wm = weston_wm_create(wxs);
167 if (wxs->wm == NULL) {
168 weston_log("failed to create wm\n");
171 xserver_send_listen_socket(wxs->resource, wxs->abstract_fd);
172 xserver_send_listen_socket(wxs->resource, wxs->unix_fd);
176 bind_to_abstract_socket(int display)
178 struct sockaddr_un addr;
179 socklen_t size, name_size;
182 fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
186 addr.sun_family = AF_LOCAL;
187 name_size = snprintf(addr.sun_path, sizeof addr.sun_path,
188 "%c/tmp/.X11-unix/X%d", 0, display);
189 size = offsetof(struct sockaddr_un, sun_path) + name_size;
190 if (bind(fd, (struct sockaddr *) &addr, size) < 0) {
191 weston_log("failed to bind to @%s: %s\n",
192 addr.sun_path + 1, strerror(errno));
197 if (listen(fd, 1) < 0) {
206 bind_to_unix_socket(int display)
208 struct sockaddr_un addr;
209 socklen_t size, name_size;
212 fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
216 addr.sun_family = AF_LOCAL;
217 name_size = snprintf(addr.sun_path, sizeof addr.sun_path,
218 "/tmp/.X11-unix/X%d", display) + 1;
219 size = offsetof(struct sockaddr_un, sun_path) + name_size;
220 unlink(addr.sun_path);
221 if (bind(fd, (struct sockaddr *) &addr, size) < 0) {
222 weston_log("failed to bind to %s (%s)\n",
223 addr.sun_path, strerror(errno));
228 if (listen(fd, 1) < 0) {
229 unlink(addr.sun_path);
238 create_lockfile(int display, char *lockfile, size_t lsize)
244 snprintf(lockfile, lsize, "/tmp/.X%d-lock", display);
245 fd = open(lockfile, O_WRONLY | O_CLOEXEC | O_CREAT | O_EXCL, 0444);
246 if (fd < 0 && errno == EEXIST) {
247 fd = open(lockfile, O_CLOEXEC, O_RDONLY);
248 if (fd < 0 || read(fd, pid, 11) != 11) {
249 weston_log("can't read lock file %s: %s\n",
250 lockfile, strerror(errno));
255 other = strtol(pid, &end, 0);
256 if (end != pid + 10) {
257 weston_log("can't parse lock file %s\n",
264 if (kill(other, 0) < 0 && errno == ESRCH) {
265 /* stale lock file; unlink and try again */
266 weston_log("unlinking stale lock file %s\n", lockfile);
268 if (unlink(lockfile))
269 /* If we fail to unlink, return EEXIST
270 so we try the next display number.*/
281 weston_log("failed to create lock file %s: %s\n",
282 lockfile, strerror(errno));
286 /* Subtle detail: we use the pid of the wayland
287 * compositor, not the xserver in the lock file. */
288 size = snprintf(pid, sizeof pid, "%10d\n", getpid());
289 if (write(fd, pid, size) != size) {
301 weston_xserver_destroy(struct wl_listener *l, void *data)
303 struct weston_xserver *wxs =
304 container_of(l, struct weston_xserver, destroy_listener);
310 weston_xserver_shutdown(wxs);
316 weston_xserver_init(struct weston_compositor *compositor)
318 struct wl_display *display = compositor->wl_display;
319 struct weston_xserver *mxs;
320 char lockfile[256], display_name[8];
322 mxs = malloc(sizeof *mxs);
323 memset(mxs, 0, sizeof *mxs);
325 mxs->process.cleanup = weston_xserver_cleanup;
326 mxs->wl_display = display;
327 mxs->compositor = compositor;
332 if (create_lockfile(mxs->display, lockfile, sizeof lockfile) < 0) {
333 if (errno == EAGAIN) {
335 } else if (errno == EEXIST) {
344 mxs->abstract_fd = bind_to_abstract_socket(mxs->display);
345 if (mxs->abstract_fd < 0 && errno == EADDRINUSE) {
351 mxs->unix_fd = bind_to_unix_socket(mxs->display);
352 if (mxs->unix_fd < 0) {
354 close(mxs->abstract_fd);
359 snprintf(display_name, sizeof display_name, ":%d", mxs->display);
360 weston_log("xserver listening on display %s\n", display_name);
361 setenv("DISPLAY", display_name, 1);
363 mxs->loop = wl_display_get_event_loop(display);
364 mxs->abstract_source =
365 wl_event_loop_add_fd(mxs->loop, mxs->abstract_fd,
367 weston_xserver_handle_event, mxs);
369 wl_event_loop_add_fd(mxs->loop, mxs->unix_fd,
371 weston_xserver_handle_event, mxs);
373 wl_display_add_global(display, &xserver_interface, mxs, bind_xserver);
375 mxs->destroy_listener.notify = weston_xserver_destroy;
376 wl_signal_add(&compositor->destroy_signal, &mxs->destroy_listener);