diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h index 679e31804..46a2470a7 100644 --- a/src/wayland/meta-wayland-private.h +++ b/src/wayland/meta-wayland-private.h @@ -46,6 +46,7 @@ typedef struct { int display_index; char *lock_file; + int abstract_fd; int unix_fd; char *name; } MetaXWaylandConnection; diff --git a/src/wayland/meta-xwayland.c b/src/wayland/meta-xwayland.c index 53017c357..783a58d35 100644 --- a/src/wayland/meta-xwayland.c +++ b/src/wayland/meta-xwayland.c @@ -438,6 +438,51 @@ create_lock_file (int display, return filename; } +static int +bind_to_abstract_socket (int display, + gboolean *fatal, + GError **error) +{ + struct sockaddr_un addr; + socklen_t size, name_size; + int fd; + + fd = socket (PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (fd < 0) + { + *fatal = TRUE; + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), + "Failed to create socket: %s", g_strerror (errno)); + return -1; + } + + addr.sun_family = AF_LOCAL; + name_size = snprintf (addr.sun_path, sizeof addr.sun_path, + "%c/tmp/.X11-unix/X%d", 0, display); + size = offsetof (struct sockaddr_un, sun_path) + name_size; + if (bind (fd, (struct sockaddr *) &addr, size) < 0) + { + *fatal = errno != EADDRINUSE; + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), + "Failed to bind to %s: %s", + addr.sun_path + 1, g_strerror (errno)); + close (fd); + return -1; + } + + if (listen (fd, 1) < 0) + { + *fatal = errno != EADDRINUSE; + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), + "Failed to listen to %s: %s", + addr.sun_path + 1, g_strerror (errno)); + close (fd); + return -1; + } + + return fd; +} + static int bind_to_unix_socket (int display, GError **error) @@ -597,18 +642,29 @@ ensure_x11_unix_dir (GError **error) static gboolean open_display_sockets (MetaXWaylandManager *manager, int display_index, + int *abstract_fd_out, int *unix_fd_out, + gboolean *fatal, GError **error) { - int unix_fd; + int abstract_fd, unix_fd; if (!ensure_x11_unix_dir (error)) return FALSE; - unix_fd = bind_to_unix_socket (display_index, error); - if (unix_fd < 0) + abstract_fd = bind_to_abstract_socket (display_index, fatal, error); + if (abstract_fd < 0) return FALSE; + unix_fd = bind_to_unix_socket (display_index, error); + if (unix_fd < 0) + { + *fatal = FALSE; + close (abstract_fd); + return FALSE; + } + + *abstract_fd_out = abstract_fd; *unix_fd_out = unix_fd; return TRUE; @@ -621,6 +677,7 @@ choose_xdisplay (MetaXWaylandManager *manager, { int display = 0; char *lock_file = NULL; + gboolean fatal = FALSE; if (display_number_override != -1) display = display_number_override; @@ -640,12 +697,23 @@ choose_xdisplay (MetaXWaylandManager *manager, } if (!open_display_sockets (manager, display, + &connection->abstract_fd, &connection->unix_fd, + &fatal, &local_error)) { unlink (lock_file); - g_prefix_error (error, "Failed to bind X11 socket: "); - return FALSE; + + if (!fatal) + { + display++; + continue; + } + else + { + g_warning ("Failed to bind X11 socket"); + return FALSE; + } } break; @@ -843,9 +911,10 @@ meta_xwayland_start_xserver (MetaXWaylandManager *manager, launcher = g_subprocess_launcher_new (flags); g_subprocess_launcher_take_fd (launcher, xwayland_client_fd[1], 3); - g_subprocess_launcher_take_fd (launcher, manager->public_connection.unix_fd, 4); - g_subprocess_launcher_take_fd (launcher, displayfd[1], 5); - g_subprocess_launcher_take_fd (launcher, manager->private_connection.unix_fd, 6); + g_subprocess_launcher_take_fd (launcher, manager->public_connection.abstract_fd, 4); + g_subprocess_launcher_take_fd (launcher, manager->public_connection.unix_fd, 5); + g_subprocess_launcher_take_fd (launcher, displayfd[1], 6); + g_subprocess_launcher_take_fd (launcher, manager->private_connection.abstract_fd, 7); g_subprocess_launcher_setenv (launcher, "WAYLAND_SOCKET", "3", TRUE); @@ -860,14 +929,16 @@ meta_xwayland_start_xserver (MetaXWaylandManager *manager, args[i++] = manager->auth_file; args[i++] = "-listen"; args[i++] = "4"; - args[i++] = "-displayfd"; + args[i++] = "-listen"; args[i++] = "5"; + args[i++] = "-displayfd"; + args[i++] = "6"; #ifdef HAVE_XWAYLAND_INITFD args[i++] = "-initfd"; - args[i++] = "6"; + args[i++] = "7"; #else args[i++] = "-listen"; - args[i++] = "6"; + args[i++] = "7"; #endif for (j = 0; j < G_N_ELEMENTS (x11_extension_names); j++) { @@ -987,6 +1058,7 @@ meta_xwayland_init (MetaXWaylandManager *manager, GError **error) { MetaDisplayPolicy policy; + gboolean fatal; if (!manager->public_connection.name) { @@ -1002,13 +1074,17 @@ meta_xwayland_init (MetaXWaylandManager *manager, { if (!open_display_sockets (manager, manager->public_connection.display_index, + &manager->public_connection.abstract_fd, &manager->public_connection.unix_fd, + &fatal, error)) return FALSE; if (!open_display_sockets (manager, manager->private_connection.display_index, + &manager->private_connection.abstract_fd, &manager->private_connection.unix_fd, + &fatal, error)) return FALSE; } @@ -1022,7 +1098,7 @@ meta_xwayland_init (MetaXWaylandManager *manager, if (policy == META_DISPLAY_POLICY_ON_DEMAND) { - g_unix_fd_add (manager->public_connection.unix_fd, G_IO_IN, + g_unix_fd_add (manager->public_connection.abstract_fd, G_IO_IN, xdisplay_connection_activity_cb, manager); }