2014-07-02 08:46:22 -07:00
|
|
|
#include "e.h"
|
2014-07-06 07:12:03 -07:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/un.h>
|
2014-07-02 08:46:22 -07:00
|
|
|
|
|
|
|
/* local structures */
|
|
|
|
typedef struct _E_XWayland_Server E_XWayland_Server;
|
|
|
|
struct _E_XWayland_Server
|
|
|
|
{
|
|
|
|
int disp;
|
2014-07-06 07:51:01 -07:00
|
|
|
int abs_fd, unx_fd, wm_fd;
|
2014-07-06 07:12:03 -07:00
|
|
|
char lock[256];
|
|
|
|
|
2014-07-06 07:51:01 -07:00
|
|
|
struct wl_display *wl_disp;
|
2014-07-06 07:12:03 -07:00
|
|
|
struct wl_event_loop *loop;
|
|
|
|
|
|
|
|
Ecore_Fd_Handler *abs_hdlr, *unx_hdlr;
|
|
|
|
Ecore_Event_Handler *sig_hdlr;
|
|
|
|
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
pid_t pid;
|
|
|
|
/* cleanup_func func; */
|
|
|
|
} process;
|
2014-07-02 08:46:22 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
/* local variables */
|
|
|
|
static E_XWayland_Server *exs;
|
|
|
|
|
|
|
|
/* local functions */
|
2015-07-02 10:55:42 -07:00
|
|
|
static int
|
|
|
|
_lock_create(int lock)
|
2014-07-02 08:46:22 -07:00
|
|
|
{
|
2014-07-06 07:12:03 -07:00
|
|
|
char pid[16], *end;
|
2014-07-02 08:46:22 -07:00
|
|
|
int fd, size;
|
|
|
|
pid_t opid;
|
|
|
|
|
2015-07-02 10:55:42 -07:00
|
|
|
/* assemble lock file name */
|
|
|
|
snprintf(exs->lock, sizeof(exs->lock), "/tmp/.X%d-lock", lock);
|
|
|
|
|
|
|
|
fd = open(exs->lock, (O_WRONLY | O_CLOEXEC | O_CREAT | O_EXCL), 0444);
|
2014-07-02 08:46:22 -07:00
|
|
|
if ((fd < 0) && (errno == EEXIST))
|
|
|
|
{
|
2015-07-02 10:55:42 -07:00
|
|
|
fd = open(exs->lock, (O_CLOEXEC | O_RDONLY));
|
2014-07-02 08:46:22 -07:00
|
|
|
if ((fd < 0) || (read(fd, pid, 11) != 11))
|
|
|
|
{
|
|
|
|
ERR("Could not read XWayland lock file: %m");
|
|
|
|
if (fd >= 0) close(fd);
|
2015-07-02 10:55:42 -07:00
|
|
|
return EEXIST;
|
2014-07-02 08:46:22 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
opid = strtol(pid, &end, 0);
|
|
|
|
if ((end != (pid + 10)))
|
|
|
|
{
|
|
|
|
if (fd >= 0) close(fd);
|
2015-07-02 10:55:42 -07:00
|
|
|
return EEXIST;
|
2014-07-02 08:46:22 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((kill(opid, 0) < 0) && (errno == ESRCH))
|
|
|
|
{
|
|
|
|
/* close stale lock file */
|
|
|
|
if (fd >= 0) close(fd);
|
|
|
|
|
2015-07-02 10:55:42 -07:00
|
|
|
if (unlink(exs->lock))
|
|
|
|
return EEXIST;
|
|
|
|
return EAGAIN;
|
2014-07-02 08:46:22 -07:00
|
|
|
}
|
|
|
|
close(fd);
|
2015-07-02 10:55:42 -07:00
|
|
|
return EEXIST;
|
2014-07-02 08:46:22 -07:00
|
|
|
}
|
|
|
|
else if (fd < 0)
|
|
|
|
{
|
|
|
|
ERR("Could not create XWayland lock file: %m");
|
2015-07-02 10:55:42 -07:00
|
|
|
return 0;
|
2014-07-02 08:46:22 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* use the pid of the wayland compositor */
|
|
|
|
size = snprintf(pid, sizeof(pid), "%10d\n", getpid());
|
|
|
|
if (write(fd, pid, size) != size)
|
|
|
|
{
|
2015-07-02 10:55:42 -07:00
|
|
|
unlink(exs->lock);
|
2014-07-02 08:46:22 -07:00
|
|
|
close(fd);
|
2015-07-02 10:55:42 -07:00
|
|
|
return 0;
|
2014-07-02 08:46:22 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
|
2015-07-02 10:55:42 -07:00
|
|
|
return 1;
|
2014-07-02 08:46:22 -07:00
|
|
|
}
|
|
|
|
|
2014-07-06 07:12:03 -07:00
|
|
|
static int
|
|
|
|
_abstract_socket_bind(int disp)
|
|
|
|
{
|
|
|
|
struct sockaddr_un addr;
|
|
|
|
socklen_t size, nsize;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
/* try to create a local socket */
|
|
|
|
if ((fd = socket(PF_LOCAL, (SOCK_STREAM | SOCK_CLOEXEC), 0)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2015-06-30 12:37:56 -07:00
|
|
|
ecore_file_mkpath("/tmp/.X11-unix");
|
|
|
|
|
2014-07-06 07:12:03 -07:00
|
|
|
addr.sun_family = AF_LOCAL;
|
|
|
|
nsize = snprintf(addr.sun_path, sizeof(addr.sun_path),
|
|
|
|
"%c/tmp/.X11-unix/X%d", 0, disp);
|
|
|
|
size = offsetof(struct sockaddr_un, sun_path) + nsize;
|
|
|
|
|
|
|
|
/* try to bind to the socket */
|
|
|
|
if (bind(fd, (struct sockaddr *)&addr, size) < 0)
|
|
|
|
{
|
|
|
|
ERR("Failed to bind to abstract socket %s: %m", addr.sun_path + 1);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* try to listen on the bound socket */
|
2014-07-15 10:54:55 -07:00
|
|
|
if (listen(fd, 1) < 0)
|
|
|
|
{
|
|
|
|
ERR("Failed to listen to abstract fd: %d", fd);
|
|
|
|
goto err;
|
|
|
|
}
|
2014-07-06 07:12:03 -07:00
|
|
|
|
|
|
|
return fd;
|
|
|
|
|
|
|
|
err:
|
|
|
|
close(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
_unix_socket_bind(int disp)
|
|
|
|
{
|
|
|
|
struct sockaddr_un addr;
|
|
|
|
socklen_t size, nsize;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
/* try to create a local socket */
|
|
|
|
if ((fd = socket(PF_LOCAL, (SOCK_STREAM | SOCK_CLOEXEC), 0)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
addr.sun_family = AF_LOCAL;
|
|
|
|
nsize = snprintf(addr.sun_path, sizeof(addr.sun_path),
|
|
|
|
"/tmp/.X11-unix/X%d", disp) + 1;
|
|
|
|
size = offsetof(struct sockaddr_un, sun_path) + nsize;
|
|
|
|
|
|
|
|
unlink(addr.sun_path);
|
|
|
|
|
|
|
|
/* try to bind to the socket */
|
|
|
|
if (bind(fd, (struct sockaddr *)&addr, size) < 0)
|
|
|
|
{
|
|
|
|
ERR("Failed to bind to abstract socket %s: %m", addr.sun_path + 1);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* try to listen on the bound socket */
|
2014-07-15 10:54:55 -07:00
|
|
|
if (listen(fd, 1) < 0)
|
|
|
|
{
|
|
|
|
ERR("Failed to listen to unix fd: %d", fd);
|
|
|
|
goto err;
|
|
|
|
}
|
2014-07-06 07:12:03 -07:00
|
|
|
|
|
|
|
return fd;
|
|
|
|
|
|
|
|
err:
|
|
|
|
close(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
|
|
|
_cb_xserver_event(void *data EINA_UNUSED, Ecore_Fd_Handler *hdlr EINA_UNUSED)
|
|
|
|
{
|
|
|
|
int socks[2], wms[2], fd;
|
2014-07-15 07:58:48 -07:00
|
|
|
char disp[8], s[8], xserver[PATH_MAX];
|
2014-07-06 07:12:03 -07:00
|
|
|
char abs_fd[8], unx_fd[8], wm_fd[8];
|
|
|
|
|
|
|
|
if (socketpair(AF_UNIX, (SOCK_STREAM | SOCK_CLOEXEC), 0, socks) < 0)
|
|
|
|
{
|
|
|
|
ERR("XServer Socketpair failed: %m");
|
|
|
|
return ECORE_CALLBACK_RENEW;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (socketpair(AF_UNIX, (SOCK_STREAM | SOCK_CLOEXEC), 0, wms) < 0)
|
|
|
|
{
|
|
|
|
ERR("Window Manager Socketpair failed: %m");
|
|
|
|
return ECORE_CALLBACK_RENEW;
|
|
|
|
}
|
|
|
|
|
|
|
|
exs->process.pid = fork();
|
|
|
|
switch (exs->process.pid)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
/* dup will unset CLOEXEC on the client as cloexec closes both ends */
|
2015-04-28 13:58:55 -07:00
|
|
|
fd = dup(socks[1]);
|
|
|
|
if (fd < 0) goto fail;
|
2014-07-06 07:12:03 -07:00
|
|
|
snprintf(s, sizeof(s), "%d", fd);
|
|
|
|
setenv("WAYLAND_SOCKET", s, 1);
|
|
|
|
|
2015-04-28 13:58:55 -07:00
|
|
|
fd = dup(exs->abs_fd);
|
|
|
|
if (fd < 0) goto fail;
|
2014-07-06 07:12:03 -07:00
|
|
|
snprintf(abs_fd, sizeof(abs_fd), "%d", fd);
|
|
|
|
|
2015-04-28 13:58:55 -07:00
|
|
|
fd = dup(exs->unx_fd);
|
|
|
|
if (fd < 0) goto fail;
|
2014-07-06 07:12:03 -07:00
|
|
|
snprintf(unx_fd, sizeof(unx_fd), "%d", fd);
|
|
|
|
|
2015-04-28 13:58:55 -07:00
|
|
|
fd = dup(wms[1]);
|
|
|
|
if (fd < 0) goto fail;
|
2014-07-06 07:12:03 -07:00
|
|
|
snprintf(wm_fd, sizeof(wm_fd), "%d", fd);
|
|
|
|
|
|
|
|
/* ignore usr1 and have X send it to the parent process */
|
|
|
|
signal(SIGUSR1, SIG_IGN);
|
|
|
|
|
|
|
|
snprintf(disp, sizeof(disp), ":%d", exs->disp);
|
|
|
|
|
2014-07-15 07:58:48 -07:00
|
|
|
snprintf(xserver, sizeof(xserver), "%s", XWAYLAND_BIN);
|
2014-07-15 10:54:55 -07:00
|
|
|
DBG("\tLaunching XWayland: %s: %s", xserver, disp);
|
2014-07-06 07:12:03 -07:00
|
|
|
if (execl(xserver, xserver, disp, "-rootless", "-listen", abs_fd,
|
2015-06-25 15:41:07 -07:00
|
|
|
"-listen", unx_fd, "-terminate", "-shm",
|
2014-07-15 10:54:55 -07:00
|
|
|
NULL) < 0)
|
2014-07-06 07:12:03 -07:00
|
|
|
{
|
|
|
|
ERR("Failed to exec XWayland: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
fail:
|
|
|
|
_exit(EXIT_FAILURE);
|
|
|
|
|
|
|
|
default:
|
|
|
|
close(socks[1]);
|
2015-06-25 15:41:07 -07:00
|
|
|
e_comp->wl_comp_data->xwl_client = wl_client_create(exs->wl_disp, socks[0]);
|
2014-07-06 07:51:01 -07:00
|
|
|
|
2014-07-06 07:12:03 -07:00
|
|
|
close(wms[1]);
|
2014-07-06 07:51:01 -07:00
|
|
|
exs->wm_fd = wms[0];
|
|
|
|
|
2014-09-08 09:30:34 -07:00
|
|
|
/* TODO: watch process ?? */
|
|
|
|
|
2014-07-15 10:54:55 -07:00
|
|
|
if (exs->abs_hdlr)
|
|
|
|
ecore_main_fd_handler_del(exs->abs_hdlr);
|
|
|
|
if (exs->unx_hdlr)
|
|
|
|
ecore_main_fd_handler_del(exs->unx_hdlr);
|
2014-07-06 07:12:03 -07:00
|
|
|
break;
|
|
|
|
case -1:
|
|
|
|
ERR("Failed to fork: %m");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ECORE_CALLBACK_RENEW;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
2014-09-05 12:00:00 -07:00
|
|
|
_cb_signal_event(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
|
2014-07-06 07:12:03 -07:00
|
|
|
{
|
2014-09-05 12:00:00 -07:00
|
|
|
Ecore_Event_Signal_User *ev;
|
2015-06-25 15:41:07 -07:00
|
|
|
char buf[128];
|
2014-09-05 12:00:00 -07:00
|
|
|
|
|
|
|
ev = event;
|
|
|
|
if (ev->number != 1) return ECORE_CALLBACK_RENEW;
|
|
|
|
|
2014-07-06 07:12:03 -07:00
|
|
|
/* NB: SIGUSR1 comes from XWayland Server when it has finished
|
|
|
|
* initialized. */
|
|
|
|
|
2014-07-15 07:58:48 -07:00
|
|
|
DBG("XWayland Finished Init");
|
2015-06-25 15:41:07 -07:00
|
|
|
snprintf(buf, sizeof(buf), ":%d", exs->disp);
|
|
|
|
assert(ecore_x_init(buf));
|
|
|
|
e_comp_x_init();
|
2014-07-06 07:51:01 -07:00
|
|
|
|
2014-07-15 10:54:55 -07:00
|
|
|
return ECORE_CALLBACK_CANCEL;
|
2014-07-06 07:12:03 -07:00
|
|
|
}
|
|
|
|
|
2015-07-02 10:55:42 -07:00
|
|
|
static Eina_Bool
|
|
|
|
setup_lock(void)
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
|
|
|
/* try to create the xserver lock file */
|
|
|
|
switch (_lock_create(exs->disp))
|
|
|
|
{
|
|
|
|
case EEXIST:
|
|
|
|
exs->disp++;
|
|
|
|
case EAGAIN:
|
|
|
|
continue;
|
|
|
|
case 0:
|
|
|
|
free(exs);
|
|
|
|
return EINA_FALSE;
|
|
|
|
default:
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
} while (1);
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
2015-07-02 11:26:40 -07:00
|
|
|
static Eina_Bool
|
|
|
|
error_dialog()
|
|
|
|
{
|
|
|
|
e_util_dialog_internal(_("Error"), _("Cannot launch XWayland from X11 display."));
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
2014-07-02 08:46:22 -07:00
|
|
|
/* module functions */
|
2015-07-01 09:43:05 -07:00
|
|
|
E_API E_Module_Api e_modapi = { E_MODULE_API_VERSION, "XWayland" };
|
2014-07-02 08:46:22 -07:00
|
|
|
|
2015-07-01 09:43:05 -07:00
|
|
|
E_API void *
|
2014-07-02 08:46:22 -07:00
|
|
|
e_modapi_init(E_Module *m)
|
|
|
|
{
|
2014-07-06 07:12:03 -07:00
|
|
|
char disp[8];
|
2014-07-02 08:46:22 -07:00
|
|
|
|
|
|
|
/* make sure it's a wayland compositor */
|
2015-04-28 10:25:53 -07:00
|
|
|
if (e_comp->comp_type != E_PIXMAP_TYPE_WL) return NULL;
|
2014-07-02 08:46:22 -07:00
|
|
|
|
2015-07-02 11:26:40 -07:00
|
|
|
if (getenv("DISPLAY"))
|
|
|
|
{
|
|
|
|
ecore_timer_add(1.0, error_dialog, NULL);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-07-01 13:02:48 -07:00
|
|
|
DBG("LOAD XWAYLAND MODULE");
|
|
|
|
|
2014-07-02 08:46:22 -07:00
|
|
|
/* alloc space for server struct */
|
|
|
|
if (!(exs = calloc(1, sizeof(E_XWayland_Server))))
|
|
|
|
return NULL;
|
|
|
|
|
2014-07-06 07:51:01 -07:00
|
|
|
/* record wayland display */
|
2015-04-28 10:25:53 -07:00
|
|
|
exs->wl_disp = e_comp->wl_comp_data->wl.disp;
|
2014-07-06 07:51:01 -07:00
|
|
|
|
2014-07-02 08:46:22 -07:00
|
|
|
/* default display to zero */
|
|
|
|
exs->disp = 0;
|
|
|
|
|
2015-07-02 10:55:42 -07:00
|
|
|
do
|
2014-07-02 08:46:22 -07:00
|
|
|
{
|
2015-07-02 10:55:42 -07:00
|
|
|
if (!setup_lock()) return NULL;
|
|
|
|
|
|
|
|
/* try to bind abstract socket */
|
|
|
|
exs->abs_fd = _abstract_socket_bind(exs->disp);
|
|
|
|
if ((exs->abs_fd < 0) && (errno == EADDRINUSE))
|
2014-07-02 08:46:22 -07:00
|
|
|
{
|
|
|
|
exs->disp++;
|
2015-07-02 10:55:42 -07:00
|
|
|
unlink(exs->lock);
|
|
|
|
continue;
|
2014-07-02 08:46:22 -07:00
|
|
|
}
|
2015-07-02 10:55:42 -07:00
|
|
|
|
|
|
|
/* try to bind unix socket */
|
|
|
|
exs->unx_fd = _unix_socket_bind(exs->disp);
|
|
|
|
if (exs->unx_fd < 0)
|
2014-07-02 08:46:22 -07:00
|
|
|
{
|
2015-07-02 10:55:42 -07:00
|
|
|
unlink(exs->lock);
|
|
|
|
close(exs->abs_fd);
|
2014-07-02 08:46:22 -07:00
|
|
|
free(exs);
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-07-02 10:55:42 -07:00
|
|
|
break;
|
|
|
|
} while (1);
|
2014-07-06 07:12:03 -07:00
|
|
|
|
|
|
|
/* assemble x11 display name and set it */
|
|
|
|
snprintf(disp, sizeof(disp), ":%d", exs->disp);
|
2014-07-15 10:54:55 -07:00
|
|
|
DBG("XWayland Listening on display: %s", disp);
|
2014-07-06 07:12:03 -07:00
|
|
|
setenv("DISPLAY", disp, 1);
|
|
|
|
|
|
|
|
/* setup ecore_fd handlers for abstract and unix socket fds */
|
|
|
|
exs->abs_hdlr =
|
|
|
|
ecore_main_fd_handler_add(exs->abs_fd, ECORE_FD_READ,
|
|
|
|
_cb_xserver_event, NULL, NULL, NULL);
|
|
|
|
exs->unx_hdlr =
|
|
|
|
ecore_main_fd_handler_add(exs->unx_fd, ECORE_FD_READ,
|
|
|
|
_cb_xserver_event, NULL, NULL, NULL);
|
|
|
|
|
|
|
|
/* setup listener for SIGUSR1 */
|
|
|
|
exs->sig_hdlr =
|
|
|
|
ecore_event_handler_add(ECORE_EVENT_SIGNAL_USER, _cb_signal_event, exs);
|
2014-07-02 08:46:22 -07:00
|
|
|
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
2015-07-01 09:43:05 -07:00
|
|
|
E_API int
|
2014-07-06 07:12:03 -07:00
|
|
|
e_modapi_shutdown(E_Module *m EINA_UNUSED)
|
2014-07-02 08:46:22 -07:00
|
|
|
{
|
2014-09-08 09:30:34 -07:00
|
|
|
char path[256];
|
|
|
|
|
|
|
|
if (!exs) return 1;
|
|
|
|
|
|
|
|
unlink(exs->lock);
|
|
|
|
|
|
|
|
snprintf(path, sizeof(path), "/tmp/.X11-unix/X%d", exs->disp);
|
|
|
|
unlink(path);
|
|
|
|
|
|
|
|
if (exs->abs_hdlr) ecore_main_fd_handler_del(exs->abs_hdlr);
|
|
|
|
if (exs->unx_hdlr) ecore_main_fd_handler_del(exs->unx_hdlr);
|
|
|
|
|
|
|
|
close(exs->abs_fd);
|
|
|
|
close(exs->unx_fd);
|
|
|
|
|
|
|
|
if (exs->sig_hdlr) ecore_event_handler_del(exs->sig_hdlr);
|
|
|
|
|
|
|
|
free(exs);
|
|
|
|
|
2014-07-02 08:46:22 -07:00
|
|
|
return 1;
|
|
|
|
}
|