xwayland: Fork the X server ourselves

gspawn just isn't us the fine-grained control we need for starting
processes and leaking file descriptors in.
This commit is contained in:
Jasper St. Pierre 2014-04-01 19:51:43 -04:00
parent c540ddf59b
commit 5cf0740b4e

View File

@ -251,18 +251,6 @@ bind_to_unix_socket (int display)
return fd; return fd;
} }
static void
uncloexec (gpointer user_data)
{
int fd = GPOINTER_TO_INT (user_data);
/* Make sure the client end of the socket pair doesn't get closed
* when we exec xwayland. */
int flags = fcntl (fd, F_GETFD);
if (flags != -1)
fcntl (fd, F_SETFD, flags & ~FD_CLOEXEC);
}
static void static void
xserver_died (GPid pid, xserver_died (GPid pid,
gint status, gint status,
@ -341,9 +329,8 @@ meta_xwayland_start (MetaXWaylandManager *manager,
struct wl_display *wl_display) struct wl_display *wl_display)
{ {
int sp[2]; int sp[2];
pid_t pid; int fd;
char **env; char *socket_fd;
char *fd_string;
if (!choose_xdisplay (manager)) if (!choose_xdisplay (manager))
return FALSE; return FALSE;
@ -361,56 +348,42 @@ meta_xwayland_start (MetaXWaylandManager *manager,
return 1; return 1;
} }
env = g_get_environ (); manager->pid = fork ();
fd_string = g_strdup_printf ("%d", sp[1]); if (manager->pid == 0)
env = g_environ_setenv (env, "WAYLAND_SOCKET", fd_string, TRUE);
g_free (fd_string);
{ {
GError *error = NULL; /* We passed SOCK_CLOEXEC, so dup the FD so it isn't
gchar *args[] = { XWAYLAND_PATH, * closed on exec.. */
fd = dup (sp[1]);
socket_fd = g_strdup_printf ("%d", fd);
setenv ("WAYLAND_SOCKET", socket_fd, TRUE);
g_free (socket_fd);
/* xwayland, please. */
if (g_getenv ("XWAYLAND_STFU"))
{
int dev_null;
dev_null = open ("/dev/null", O_WRONLY);
dup2 (dev_null, STDOUT_FILENO);
dup2 (dev_null, STDERR_FILENO);
}
if (execl (XWAYLAND_PATH, XWAYLAND_PATH,
manager->display_name, manager->display_name,
"-wayland", "-wayland",
"-rootless", "-rootless",
"-noreset", "-noreset",
"-nolisten", "-nolisten", "all",
"all", NULL) < 0)
NULL };
int flags = 0;
flags |= G_SPAWN_LEAVE_DESCRIPTORS_OPEN;
flags |= G_SPAWN_DO_NOT_REAP_CHILD;
/* xwayland, please. */
if (getenv ("XWAYLAND_STFU"))
{ {
flags |= G_SPAWN_STDOUT_TO_DEV_NULL; g_warning ("Failed to spawn XWayland: %m");
flags |= G_SPAWN_STDERR_TO_DEV_NULL; exit (EXIT_FAILURE);
}
} }
if (g_spawn_async (NULL, /* cwd */ g_child_watch_add (manager->pid, xserver_died, NULL);
args,
env,
flags,
uncloexec,
GINT_TO_POINTER (sp[1]),
&pid,
&error))
{
close (sp[1]);
manager->client = wl_client_create (wl_display, sp[0]); manager->client = wl_client_create (wl_display, sp[0]);
manager->pid = pid;
g_child_watch_add (pid, xserver_died, NULL);
}
else
{
g_error ("Failed to fork for xwayland server: %s", error->message);
}
}
g_strfreev (env);
/* We need to run a mainloop until we know xwayland has a binding /* We need to run a mainloop until we know xwayland has a binding
* for our xserver interface at which point we can assume it's * for our xserver interface at which point we can assume it's
* ready to start accepting connections. */ * ready to start accepting connections. */