parent
57eca7424a
commit
27da538ab5
@ -0,0 +1,206 @@ |
|||||||
|
/*
|
||||||
|
* Copyright © 2011 Intel Corporation |
||||||
|
* |
||||||
|
* Permission to use, copy, modify, distribute, and sell this software and |
||||||
|
* its documentation for any purpose is hereby granted without fee, provided |
||||||
|
* that the above copyright notice appear in all copies and that both that |
||||||
|
* copyright notice and this permission notice appear in supporting |
||||||
|
* documentation, and that the name of the copyright holders not be used in |
||||||
|
* advertising or publicity pertaining to distribution of the software |
||||||
|
* without specific, written prior permission. The copyright holders make |
||||||
|
* no representations about the suitability of this software for any |
||||||
|
* purpose. It is provided "as is" without express or implied warranty. |
||||||
|
* |
||||||
|
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS |
||||||
|
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND |
||||||
|
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY |
||||||
|
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER |
||||||
|
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF |
||||||
|
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
||||||
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#define _GNU_SOURCE |
||||||
|
|
||||||
|
#include <stdlib.h> |
||||||
|
#include <stdio.h> |
||||||
|
#include <string.h> |
||||||
|
#include <sys/socket.h> |
||||||
|
#include <sys/un.h> |
||||||
|
#include <fcntl.h> |
||||||
|
#include <errno.h> |
||||||
|
#include <unistd.h> |
||||||
|
|
||||||
|
#include <xcb/xcb.h> |
||||||
|
|
||||||
|
#include <wayland-server.h> |
||||||
|
|
||||||
|
#include "compositor.h" |
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: |
||||||
|
* - Clean X socket and lock file on exit |
||||||
|
* - Nuke lock file if process doesn't exist. |
||||||
|
*/ |
||||||
|
|
||||||
|
struct wlsc_xserver { |
||||||
|
struct wl_display *wl_display; |
||||||
|
struct wl_event_loop *loop; |
||||||
|
struct wl_event_source *source; |
||||||
|
struct wl_event_source *sigchld_source; |
||||||
|
struct wl_client *client; |
||||||
|
int fd; |
||||||
|
struct sockaddr_un addr; |
||||||
|
char lock_addr[113]; |
||||||
|
int display; |
||||||
|
struct wlsc_process process; |
||||||
|
}; |
||||||
|
|
||||||
|
static int |
||||||
|
wlsc_xserver_handle_event(int listen_fd, uint32_t mask, void *data) |
||||||
|
{ |
||||||
|
struct wlsc_xserver *mxs = data; |
||||||
|
char listen_fd_str[8], display[8], s[8]; |
||||||
|
int sv[2], flags; |
||||||
|
|
||||||
|
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) { |
||||||
|
fprintf(stderr, "socketpair failed\n"); |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
mxs->process.pid = fork(); |
||||||
|
switch (mxs->process.pid) { |
||||||
|
case 0: |
||||||
|
/* SOCK_CLOEXEC closes both ends, so we need to unset
|
||||||
|
* the flag on the client fd. */ |
||||||
|
flags = fcntl(sv[1], F_GETFD); |
||||||
|
if (flags != -1) |
||||||
|
fcntl(sv[1], F_SETFD, flags & ~FD_CLOEXEC); |
||||||
|
|
||||||
|
flags = fcntl(listen_fd, F_GETFD); |
||||||
|
if (flags != -1) |
||||||
|
fcntl(listen_fd, F_SETFD, flags & ~FD_CLOEXEC); |
||||||
|
|
||||||
|
snprintf(s, sizeof s, "%d", sv[1]); |
||||||
|
setenv("WAYLAND_SOCKET", s, 1); |
||||||
|
|
||||||
|
snprintf(listen_fd_str, sizeof listen_fd_str, "%d", listen_fd); |
||||||
|
snprintf(display, sizeof display, ":%d", mxs->display); |
||||||
|
|
||||||
|
if (execl("/usr/bin/Xorg", |
||||||
|
"/usr/bin/Xorg", |
||||||
|
display, |
||||||
|
"-wayland", |
||||||
|
// "-rootless",
|
||||||
|
"-retro", |
||||||
|
"-logfile", "/tmp/foo", |
||||||
|
"-terminate", |
||||||
|
"-socket", listen_fd_str, |
||||||
|
NULL) < 0) |
||||||
|
fprintf(stderr, "exec failed: %m\n"); |
||||||
|
exit(-1); |
||||||
|
|
||||||
|
default: |
||||||
|
fprintf(stderr, "forked X server, pid %d\n", mxs->process.pid); |
||||||
|
|
||||||
|
close(sv[1]); |
||||||
|
mxs->client = wl_client_create(mxs->wl_display, sv[0]); |
||||||
|
|
||||||
|
wlsc_watch_process(&mxs->process); |
||||||
|
|
||||||
|
wl_event_source_remove(mxs->source); |
||||||
|
break; |
||||||
|
|
||||||
|
case -1: |
||||||
|
fprintf(stderr, "failed to fork\n"); |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
static void |
||||||
|
wlsc_xserver_cleanup(struct wlsc_process *process, int status) |
||||||
|
{ |
||||||
|
struct wlsc_xserver *mxs = |
||||||
|
container_of(process, struct wlsc_xserver, process); |
||||||
|
|
||||||
|
fprintf(stderr, "xserver exited, code %d\n", status); |
||||||
|
mxs->process.pid = 0; |
||||||
|
mxs->source = |
||||||
|
wl_event_loop_add_fd(mxs->loop, mxs->fd, WL_EVENT_READABLE, |
||||||
|
wlsc_xserver_handle_event, mxs); |
||||||
|
} |
||||||
|
|
||||||
|
int |
||||||
|
wlsc_xserver_init(struct wl_display *display) |
||||||
|
{ |
||||||
|
struct wlsc_xserver *mxs; |
||||||
|
char lockfile[256], pid[16]; |
||||||
|
socklen_t size, name_size; |
||||||
|
int fd; |
||||||
|
|
||||||
|
mxs = malloc(sizeof *mxs); |
||||||
|
memset(mxs, 0, sizeof mxs); |
||||||
|
|
||||||
|
mxs->process.cleanup = wlsc_xserver_cleanup; |
||||||
|
mxs->wl_display = display; |
||||||
|
mxs->addr.sun_family = AF_LOCAL; |
||||||
|
mxs->fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); |
||||||
|
if (mxs->fd < 0) { |
||||||
|
free(mxs); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
mxs->display = 0; |
||||||
|
do { |
||||||
|
snprintf(lockfile, sizeof lockfile, |
||||||
|
"/tmp/.X%d-lock", mxs->display); |
||||||
|
fd = open(lockfile, |
||||||
|
O_WRONLY | O_CLOEXEC | O_CREAT | O_EXCL, 0444); |
||||||
|
if (fd < 0 && errno == EEXIST) { |
||||||
|
fprintf(stderr, "server %d exists\n", mxs->display); |
||||||
|
mxs->display++; |
||||||
|
continue; |
||||||
|
} else if (fd < 0) { |
||||||
|
close(mxs->fd); |
||||||
|
free(mxs); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
size = snprintf(pid, sizeof pid, "%10d\n", getpid()); |
||||||
|
write(fd, pid, size); |
||||||
|
close(fd); |
||||||
|
|
||||||
|
name_size = snprintf(mxs->addr.sun_path, |
||||||
|
sizeof mxs->addr.sun_path, |
||||||
|
"/tmp/.X11-unix/X%d", mxs->display) + 1; |
||||||
|
size = offsetof(struct sockaddr_un, sun_path) + name_size; |
||||||
|
if (bind(mxs->fd, (struct sockaddr *) &mxs->addr, size) < 0) { |
||||||
|
fprintf(stderr, "failed to bind to %s (%m)\n", |
||||||
|
mxs->addr.sun_path); |
||||||
|
unlink(lockfile); |
||||||
|
close(mxs->fd); |
||||||
|
free(mxs); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
break; |
||||||
|
} while (errno != 0); |
||||||
|
|
||||||
|
fprintf(stderr, "listening on display %d\n", mxs->display); |
||||||
|
|
||||||
|
if (listen(mxs->fd, 1) < 0) { |
||||||
|
unlink(mxs->addr.sun_path); |
||||||
|
unlink(lockfile); |
||||||
|
close(mxs->fd); |
||||||
|
free(mxs); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
mxs->loop = wl_display_get_event_loop(display); |
||||||
|
mxs->source = |
||||||
|
wl_event_loop_add_fd(mxs->loop, mxs->fd, WL_EVENT_READABLE, |
||||||
|
wlsc_xserver_handle_event, mxs); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
Loading…
Reference in new issue