diff --git a/compositor/xwayland.c b/compositor/xwayland.c index f2f9ea76..44f02016 100644 --- a/compositor/xwayland.c +++ b/compositor/xwayland.c @@ -91,11 +91,20 @@ out: return 0; } +static void +xserver_cleanup(struct weston_process *process, int status) +{ + struct wet_xwayland *wxw = + container_of(process, struct wet_xwayland, process); + + wxw->api->xserver_exited(wxw->xwayland, status); + wxw->client = NULL; +} + static pid_t spawn_xserver(void *user_data, const char *display, int abstract_fd, int unix_fd) { struct wet_xwayland *wxw = user_data; - pid_t pid; struct fdstr wayland_socket = FDSTR_INIT; struct fdstr x11_abstract_socket = FDSTR_INIT; struct fdstr x11_unix_socket = FDSTR_INIT; @@ -105,34 +114,29 @@ spawn_xserver(void *user_data, const char *display, int abstract_fd, int unix_fd struct weston_config *config = wet_get_config(wxw->compositor); struct weston_config_section *section; struct wl_event_loop *loop; - char *exec_failure_msg; - const char *cloexec_failure_msg = "Couldn't unset CLOEXEC on child FDs"; struct custom_env child_env; int no_cloexec_fds[5]; size_t num_no_cloexec_fds = 0; - size_t i; - char *const *envp; - char *const *argp; int ret; size_t written __attribute__ ((unused)); if (os_socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0, wayland_socket.fds) < 0) { weston_log("wl connection socketpair failed\n"); - return -1; + goto err; } fdstr_update_str1(&wayland_socket); no_cloexec_fds[num_no_cloexec_fds++] = wayland_socket.fds[1]; if (os_socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0, x11_wm_socket.fds) < 0) { weston_log("X wm connection socketpair failed\n"); - goto err_wayland_socket; + goto err; } fdstr_update_str1(&x11_wm_socket); no_cloexec_fds[num_no_cloexec_fds++] = x11_wm_socket.fds[1]; if (pipe2(display_pipe.fds, O_CLOEXEC) < 0) { weston_log("pipe creation for displayfd failed\n"); - goto err_x11_wm_socket; + goto err; } fdstr_update_str1(&display_pipe); no_cloexec_fds[num_no_cloexec_fds++] = display_pipe.fds[1]; @@ -148,8 +152,6 @@ spawn_xserver(void *user_data, const char *display, int abstract_fd, int unix_fd section = weston_config_get_section(config, "xwayland", NULL, NULL); weston_config_section_get_string(section, "path", &xserver, XSERVER_PATH); - str_printf(&exec_failure_msg, - "Error: executing Xwayland as '%s' failed.\n", xserver); custom_env_init_from_environ(&child_env); custom_env_set_env_var(&child_env, "WAYLAND_SOCKET", wayland_socket.str1); @@ -166,87 +168,50 @@ spawn_xserver(void *user_data, const char *display, int abstract_fd, int unix_fd custom_env_add_arg(&child_env, x11_wm_socket.str1); custom_env_add_arg(&child_env, "-terminate"); - envp = custom_env_get_envp(&child_env); - argp = custom_env_get_argp(&child_env); - - pid = fork(); - switch (pid) { - case 0: - setsid(); - - for (i = 0; i < num_no_cloexec_fds; i++) { - ret = os_fd_clear_cloexec(no_cloexec_fds[i]); - if (ret < 0) { - write(STDERR_FILENO, cloexec_failure_msg, - strlen(cloexec_failure_msg)); - _exit(EXIT_FAILURE); - } - } - - execve(xserver, argp, envp); - /* execve does not return on success, so it failed */ - - if (exec_failure_msg) { - written = write(STDERR_FILENO, exec_failure_msg, - strlen(exec_failure_msg)); - } - - _exit(EXIT_FAILURE); - - default: - close(wayland_socket.fds[1]); - wxw->client = wl_client_create(wxw->compositor->wl_display, - wayland_socket.fds[0]); - - close(x11_wm_socket.fds[1]); - wxw->wm_fd = x11_wm_socket.fds[0]; - - /* 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. */ - close(display_pipe.fds[1]); - loop = wl_display_get_event_loop(wxw->compositor->wl_display); - wxw->display_fd_source = - wl_event_loop_add_fd(loop, display_pipe.fds[0], - WL_EVENT_READABLE, - handle_display_fd, wxw); - - wxw->process.pid = pid; - wet_watch_process(wxw->compositor, &wxw->process); - break; - - case -1: - weston_log("Failed to fork to spawn xserver process\n"); - fdstr_close_all(&wayland_socket); - fdstr_close_all(&x11_wm_socket); - fdstr_close_all(&display_pipe); - break; + ret = weston_client_launch(wxw->compositor, &wxw->process, &child_env, + no_cloexec_fds, num_no_cloexec_fds, + xserver_cleanup); + if (!ret) { + weston_log("Couldn't start Xwayland\n"); + goto err; } - custom_env_fini(&child_env); - free(exec_failure_msg); + wxw->client = wl_client_create(wxw->compositor->wl_display, + wayland_socket.fds[0]); + if (!wxw->client) { + weston_log("Couldn't create client for Xwayland\n"); + goto err; + } + + wxw->wm_fd = x11_wm_socket.fds[0]; + + /* Now we can no longer fail, close the child end of our sockets */ + close(wayland_socket.fds[1]); + close(x11_wm_socket.fds[1]); + close(display_pipe.fds[1]); + + /* 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. */ + loop = wl_display_get_event_loop(wxw->compositor->wl_display); + wxw->display_fd_source = + wl_event_loop_add_fd(loop, display_pipe.fds[0], + WL_EVENT_READABLE, + handle_display_fd, wxw); + free(xserver); - return pid; + return wxw->process.pid; -err_x11_wm_socket: +err: + free(xserver); + fdstr_close_all(&display_pipe); fdstr_close_all(&x11_wm_socket); -err_wayland_socket: fdstr_close_all(&wayland_socket); return -1; } -static void -xserver_cleanup(struct weston_process *process, int status) -{ - struct wet_xwayland *wxw = - container_of(process, struct wet_xwayland, process); - - wxw->api->xserver_exited(wxw->xwayland, status); - wxw->client = NULL; -} - static void wxw_compositor_destroy(struct wl_listener *listener, void *data) {