static int weston_xserver_handle_event(int listen_fd, uint32_t mask, void *data) { struct weston_xserver *mxs = data; char display[8], s[8]; int sv[2], client_fd; if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) { weston_log("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. */ client_fd = dup(sv[1]); if (client_fd < 0) return 1; snprintf(s, sizeof s, "%d", client_fd); setenv("WAYLAND_SOCKET", s, 1); snprintf(display, sizeof display, ":%d", mxs->display); if (execl(XSERVER_PATH, XSERVER_PATH, display, "-wayland", "-rootless", "-retro", "-nolisten", "all", "-terminate", NULL) < 0) weston_log("exec failed: %m\n"); exit(-1); default: weston_log("forked X server, pid %d\n", mxs->process.pid); close(sv[1]); mxs->client = wl_client_create(mxs->wl_display, sv[0]); weston_watch_process(&mxs->process); wl_event_source_remove(mxs->abstract_source); wl_event_source_remove(mxs->unix_source); break; case -1: weston_log( "failed to fork\n"); break; } return 1; }
static pid_t spawn_xserver(struct weston_xserver *wxs) { int sv[2], wm[2]; if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) { weston_log("wl connection socketpair failed\n"); return 1; } if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, wm) < 0) { weston_log("X wm connection socketpair failed\n"); return 1; } QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); env.insert(QStringLiteral("WAYLAND_SOCKET"), QString::number(dup(sv[1]))); QString display = QStringLiteral(":%1").arg(wxs->display); QString abstract_fd = QString::number(dup(wxs->abstract_fd)); QString unix_fd = QString::number(dup(wxs->unix_fd)); QString wm_fd = QString::number(dup(wm[1])); s_process = new Process; s_process->setProcessChannelMode(QProcess::ForwardedChannels); s_process->setProcessEnvironment(env); s_process->connect(s_process, (void (QProcess::*)(int))&QProcess::finished, [wxs](int exitCode) { weston_xserver_exited(wxs, exitCode); if (s_process) { delete s_process; s_process = nullptr; } }); s_process->start(QStringLiteral("Xwayland"), { display, QStringLiteral("-rootless"), QStringLiteral("-listen"), abstract_fd, QStringLiteral("-listen"), unix_fd, QStringLiteral("-wm"), wm_fd, QStringLiteral("-terminate") }); close(sv[1]); wxs->client = wl_client_create(wxs->wl_display, sv[0]); close(wm[1]); wxs->wm_fd = wm[0]; return s_process->processId(); }
static int weston_xserver_handle_event(int listen_fd, uint32_t mask, void *data) { struct weston_xserver *wxs = data; char display[8], s[8], abstract_fd[8], unix_fd[8], wm_fd[8]; int sv[2], wm[2], fd; char *xserver = NULL; struct weston_config_section *section; if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) { weston_log("wl connection socketpair failed\n"); return 1; } if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, wm) < 0) { weston_log("X wm connection socketpair failed\n"); return 1; } wxs->process.pid = fork(); switch (wxs->process.pid) { case 0: /* SOCK_CLOEXEC closes both ends, so we need to unset * the flag on the client fd. */ fd = dup(sv[1]); if (fd < 0) goto fail; snprintf(s, sizeof s, "%d", fd); setenv("WAYLAND_SOCKET", s, 1); snprintf(display, sizeof display, ":%d", wxs->display); fd = dup(wxs->abstract_fd); if (fd < 0) goto fail; snprintf(abstract_fd, sizeof abstract_fd, "%d", fd); fd = dup(wxs->unix_fd); if (fd < 0) goto fail; snprintf(unix_fd, sizeof unix_fd, "%d", fd); fd = dup(wm[1]); if (fd < 0) goto fail; snprintf(wm_fd, sizeof wm_fd, "%d", fd); section = weston_config_get_section(wxs->compositor->config, "xwayland", NULL, NULL); weston_config_section_get_string(section, "path", &xserver, XSERVER_PATH); /* Ignore SIGUSR1 in the child, which will make the X * server send SIGUSR1 to the parent (weston) when * it's done with initialization. During * initialization the X server will round trip and * block on the wayland compositor, so avoid making * blocking requests (like xcb_connect_to_fd) until * it's done with that. */ signal(SIGUSR1, SIG_IGN); if (execl(xserver, xserver, display, "-rootless", "-listen", abstract_fd, "-listen", unix_fd, "-wm", wm_fd, "-terminate", NULL) < 0) weston_log("exec of '%s %s -rootless " "-listen %s -listen %s -wm %s " "-terminate' failed: %m\n", xserver, display, abstract_fd, unix_fd, wm_fd); fail: _exit(EXIT_FAILURE); default: weston_log("forked X server, pid %d\n", wxs->process.pid); close(sv[1]); wxs->client = wl_client_create(wxs->wl_display, sv[0]); close(wm[1]); wxs->wm_fd = wm[0]; weston_watch_process(&wxs->process); wl_event_source_remove(wxs->abstract_source); wl_event_source_remove(wxs->unix_source); break; case -1: weston_log( "failed to fork\n"); break; } return 1; }
gboolean meta_xwayland_start (MetaXWaylandManager *manager, struct wl_display *wl_display) { int xwayland_client_fd[2]; int displayfd[2]; gboolean started = FALSE; g_autoptr(GSubprocessLauncher) launcher = NULL; GSubprocessFlags flags; GSubprocess *proc; GError *error = NULL; if (!choose_xdisplay (manager)) goto out; /* We want xwayland to be a wayland client so we make a socketpair to setup a * wayland protocol connection. */ if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, xwayland_client_fd) < 0) { g_warning ("xwayland_client_fd socketpair failed\n"); goto out; } if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, displayfd) < 0) { g_warning ("displayfd socketpair failed\n"); goto out; } /* xwayland, please. */ flags = G_SUBPROCESS_FLAGS_NONE; if (getenv ("XWAYLAND_STFU")) { flags |= G_SUBPROCESS_FLAGS_STDOUT_SILENCE; flags |= G_SUBPROCESS_FLAGS_STDERR_SILENCE; } launcher = g_subprocess_launcher_new (flags); g_subprocess_launcher_take_fd (launcher, xwayland_client_fd[1], 3); g_subprocess_launcher_take_fd (launcher, manager->abstract_fd, 4); g_subprocess_launcher_take_fd (launcher, manager->unix_fd, 5); g_subprocess_launcher_take_fd (launcher, displayfd[1], 6); g_subprocess_launcher_setenv (launcher, "WAYLAND_SOCKET", "3", TRUE); proc = g_subprocess_launcher_spawn (launcher, &error, XWAYLAND_PATH, manager->display_name, "-rootless", "-noreset", "-listen", "4", "-listen", "5", "-displayfd", "6", NULL); if (!proc) { g_error ("Failed to spawn Xwayland: %s", error->message); goto out; } g_subprocess_wait_async (proc, NULL, xserver_died, NULL); g_unix_fd_add (displayfd[0], G_IO_IN, on_displayfd_ready, manager); manager->client = wl_client_create (wl_display, xwayland_client_fd[0]); /* 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 * ready to start accepting connections. */ manager->init_loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (manager->init_loop); started = TRUE; out: if (!started) { unlink (manager->lock_file); g_clear_pointer (&manager->lock_file, g_free); } return started; }