Like systemd-logind, weston-launch allows a non-privileged client to access dri and input devices. Unlike logind, it does not need dbus for communication with the client. Instead it uses a simple socketpair passed as an open fd to the client (Xorg) from the parent process.
The way weston-launch handles input devices during VT switch is slightly different from systemd-logind. To make the code work without deviating too much from systemd-logind, device path field was added to InputInfoRec. Support for weston-launch must be explicitly requested at configure time. Signed-off-by: Alex Suykov <alex.suy...@gmail.com> --- configure.ac | 15 ++ hw/xfree86/common/xf86Events.c | 2 +- hw/xfree86/common/xf86Init.c | 4 + hw/xfree86/common/xf86Xinput.c | 11 +- hw/xfree86/common/xf86Xinput.h | 2 + hw/xfree86/os-support/linux/Makefile.am | 4 + hw/xfree86/os-support/linux/lnx_platform.c | 3 + hw/xfree86/os-support/linux/weston-launch.c | 316 ++++++++++++++++++++++++++++ include/dix-config.h.in | 3 + include/weston-launch.h | 9 + 10 files changed, 365 insertions(+), 4 deletions(-) create mode 100644 hw/xfree86/os-support/linux/weston-launch.c create mode 100644 include/weston-launch.h diff --git a/configure.ac b/configure.ac index 98b8ea2ed..df8c837bb 100644 --- a/configure.ac +++ b/configure.ac @@ -579,6 +579,7 @@ AC_ARG_ENABLE(pciaccess, AS_HELP_STRING([--enable-pciaccess], [Build Xorg with p AC_ARG_ENABLE(linux_acpi, AS_HELP_STRING([--disable-linux-acpi], [Disable building ACPI support on Linux (if available).]), [enable_linux_acpi=$enableval], [enable_linux_acpi=yes]) AC_ARG_ENABLE(linux_apm, AS_HELP_STRING([--disable-linux-apm], [Disable building APM support on Linux (if available).]), [enable_linux_apm=$enableval], [enable_linux_apm=yes]) AC_ARG_ENABLE(systemd-logind, AS_HELP_STRING([--enable-systemd-logind], [Build systemd-logind support (default: auto)]), [SYSTEMD_LOGIND=$enableval], [SYSTEMD_LOGIND=auto]) +AC_ARG_ENABLE(weston-launch, AS_HELP_STRING([--enable-weston-launch], [Enable support for weston-launch protocol (default: no)]), [WESTON_LAUNCH=$enableval], [WESTON_LAUNCH=no]) AC_ARG_ENABLE(suid-wrapper, AS_HELP_STRING([--enable-suid-wrapper], [Build suid-root wrapper for legacy driver support on rootless xserver systems (default: no)]), [SUID_WRAPPER=$enableval], [SUID_WRAPPER=no]) dnl DDXes. @@ -902,6 +903,20 @@ if test "x$CONFIG_HAL" = xyes; then fi AM_CONDITIONAL(CONFIG_HAL, [test "x$CONFIG_HAL" = xyes]) +if test "x$WESTON_LAUNCH" = xauto; then + WESTON_LAUNCH=no +fi +if test "x$WESTON_LAUNCH" = xyes; then + if test "x$SYSTEMD_LOGIND" = xyes; then + AC_MSG_ERROR([cannot enable both systemd-logind and weston-launch.]) + elif test "x$SYSTEMD_LOGIND" = xauto; then + SYSTEMD_LOGIND=no + fi + + AC_DEFINE(WESTON_LAUNCH, 1, [Enable weston-launch support code]) +fi +AM_CONDITIONAL(WESTON_LAUNCH, [test "x$WESTON_LAUNCH" = xyes]) + if test "x$SYSTEMD_LOGIND" = xauto; then if test "x$HAVE_DBUS" = xyes -a "x$CONFIG_UDEV" = xyes ; then SYSTEMD_LOGIND=yes diff --git a/hw/xfree86/common/xf86Events.c b/hw/xfree86/common/xf86Events.c index 48394cd5e..e30952cab 100644 --- a/hw/xfree86/common/xf86Events.c +++ b/hw/xfree86/common/xf86Events.c @@ -529,7 +529,7 @@ xf86VTSwitch(void) #ifdef SYSTEMD_LOGIND else if (!systemd_logind_controls_session()) xf86VTEnter(); -#else +#elif !defined(WESTON_LAUNCH) else xf86VTEnter(); #endif diff --git a/hw/xfree86/common/xf86Init.c b/hw/xfree86/common/xf86Init.c index 5fbcb2869..c4ccb0906 100644 --- a/hw/xfree86/common/xf86Init.c +++ b/hw/xfree86/common/xf86Init.c @@ -55,6 +55,7 @@ #include "mi.h" #include "dbus-core.h" #include "systemd-logind.h" +#include "weston-launch.h" #include "loaderProcs.h" #ifdef XFreeXDGA @@ -446,6 +447,9 @@ InitOutput(ScreenInfo * pScreenInfo, int argc, char **argv) #ifdef SYSTEMD_LOGIND systemd_logind_init(); #endif +#ifdef WESTON_LAUNCH + weston_launch_init(); +#endif /* Do a general bus probe. This will be a PCI probe for x86 platforms */ xf86BusProbe(); diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c index 4f0ab3661..b10003d80 100644 --- a/hw/xfree86/common/xf86Xinput.c +++ b/hw/xfree86/common/xf86Xinput.c @@ -64,6 +64,7 @@ #include "extinit.h" #include "loaderProcs.h" #include "systemd-logind.h" +#include "weston-launch.h" #include "exevents.h" /* AddInputDevice */ #include "exglobals.h" @@ -745,6 +746,7 @@ xf86AllocateInput(void) pInfo->fd = -1; pInfo->type_name = "UNKNOWN"; + pInfo->path = NULL; return pInfo; } @@ -808,6 +810,9 @@ xf86DeleteInput(InputInfoPtr pInp, int flags) /* Else the entry wasn't in the xf86InputDevs list (ignore this). */ } + if (pInp->path) + free(pInp->path); + free((void *) pInp->driver); free((void *) pInp->name); xf86optionListFree(pInp->options); @@ -923,6 +928,8 @@ xf86NewInputDevice(InputInfoPtr pInfo, DeviceIntPtr *pdev, BOOL enable) if (path && drv->capabilities & XI86_DRV_CAP_SERVER_FD){ #ifdef SYSTEMD_LOGIND fd = systemd_logind_take_fd(pInfo->major, pInfo->minor, path, &paused); +#elif defined(WESTON_LAUNCH) + fd = weston_launch_open(path); #else fd = open(path, O_RDONLY | O_CLOEXEC); #endif @@ -935,18 +942,16 @@ xf86NewInputDevice(InputInfoPtr pInfo, DeviceIntPtr *pdev, BOOL enable) xorg_list_append(&new_device->node, &new_input_devices_list); systemd_logind_release_fd(pInfo->major, pInfo->minor, fd); - free(path); return BadMatch; } #endif pInfo->fd = fd; + pInfo->path = path; pInfo->flags |= XI86_SERVER_FD; pInfo->options = xf86ReplaceIntOption(pInfo->options, "fd", fd); } } - free(path); - xf86AddInput(drv, pInfo); input_lock(); diff --git a/hw/xfree86/common/xf86Xinput.h b/hw/xfree86/common/xf86Xinput.h index 0024053c7..4700557b1 100644 --- a/hw/xfree86/common/xf86Xinput.h +++ b/hw/xfree86/common/xf86Xinput.h @@ -111,6 +111,8 @@ struct _InputInfoRec { void *module; XF86OptionPtr options; InputAttributes *attrs; + + char *path; }; /* xf86Globals.c */ diff --git a/hw/xfree86/os-support/linux/Makefile.am b/hw/xfree86/os-support/linux/Makefile.am index 26e40bb93..ad4bda3df 100644 --- a/hw/xfree86/os-support/linux/Makefile.am +++ b/hw/xfree86/os-support/linux/Makefile.am @@ -26,6 +26,10 @@ LOGIND_SRCS = systemd-logind.c XORG_CFLAGS += $(DBUS_CFLAGS) endif +if WESTON_LAUNCH +LOGIND_SRCS = weston-launch.c +endif + liblinux_la_SOURCES = linux.h lnx_init.c lnx_video.c \ lnx_agp.c lnx_kmod.c lnx_bell.c lnx_platform.c \ $(srcdir)/../shared/VTsw_usl.c \ diff --git a/hw/xfree86/os-support/linux/lnx_platform.c b/hw/xfree86/os-support/linux/lnx_platform.c index fe1af0049..26f34de09 100644 --- a/hw/xfree86/os-support/linux/lnx_platform.c +++ b/hw/xfree86/os-support/linux/lnx_platform.c @@ -19,6 +19,7 @@ #include "hotplug.h" #include "systemd-logind.h" +#include "weston-launch.h" static Bool get_drm_info(struct OdevAttributes *attribs, char *path, int delayed_index) @@ -34,6 +35,8 @@ get_drm_info(struct OdevAttributes *attribs, char *path, int delayed_index) int minor = attribs->minor; fd = systemd_logind_take_fd(major, minor, path, &paused); +#elif defined(WESTON_LAUNCH) + fd = weston_launch_open(path); #else fd = open(path, O_RDWR | O_CLOEXEC); #endif diff --git a/hw/xfree86/os-support/linux/weston-launch.c b/hw/xfree86/os-support/linux/weston-launch.c new file mode 100644 index 000000000..6e9476d66 --- /dev/null +++ b/hw/xfree86/os-support/linux/weston-launch.c @@ -0,0 +1,316 @@ +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stat.h> +#ifdef HAVE_SYS_SYSMACROS_H +#include <sys/sysmacros.h> +#endif +#include <linux/major.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> + +#include "os.h" +#include "linux.h" +#include "xf86.h" +#include "xf86platformBus.h" +#include "xf86Xinput.h" +#include "xf86Priv.h" +#include "globals.h" + +#include "weston-launch.h" + +#define WESTON_LAUNCHER_OPEN 0 + +#define WESTON_LAUNCHER_ACTIVATE 1 +#define WESTON_LAUNCHER_DEACTIVATE 2 + +#ifndef WESTON_LAUNCH +# error Trying to build weston-launch.c but WESTON_LAUNCH is not defined +#endif + +static int weston_launch_fd; + +struct weston_launcher_cmd { + int opcode; +}; + +struct weston_launcher_open { + int opcode; + int flags; + char path[0]; +}; + +/* When switching out or returning to a VT, logind sends one notifications + (signal in their terms) for each managed device, and does not clearly + distinguish between inputs and drms. The X server code then needs to + match the dev against either drms (xf86_platform_devices) or inputs + (xf86InputDevs), track when all devices have been suspended/resumed. + + In contrast, both weston-launch and vtmux send a single notification + when all devices have been disabled or resumed. The X server then only + needs to disable or enable all devices it knows about. */ + +static void disable_drm_devices(void) +{ + struct xf86_platform_device *pdev = xf86_platform_devices; + struct xf86_platform_device *pend = pdev + xf86_num_platform_devices; + + for (; pdev < pend; pdev++) + pdev->flags |= XF86_PDEV_PAUSED; +} + +static void enable_drm_devices(void) +{ + struct xf86_platform_device *pdev = xf86_platform_devices; + struct xf86_platform_device *pend = pdev + xf86_num_platform_devices; + + for (; pdev < pend; pdev++) + pdev->flags &= ~XF86_PDEV_PAUSED; +} + +static void close_input_devices(void) +{ + InputInfoPtr pdev; + + for (pdev = xf86InputDevs; pdev; pdev = pdev->next) { + if (!(pdev->flags & XI86_SERVER_FD)) + continue; /* do we ever get non-server-managed devices here? */ + + xf86DisableInputDeviceForVTSwitch(pdev); + + close(pdev->fd); + pdev->fd = -1; + pdev->options = xf86ReplaceIntOption(pdev->options, "fd", pdev->fd); + } +} + +static void reopen_input_devices(void) +{ + InputInfoPtr pdev; + + for (pdev = xf86InputDevs; pdev; pdev = pdev->next) { + if (pdev->fd >= 0) + continue; + if (!pdev->path) + continue; + + pdev->fd = weston_launch_open(pdev->path); + pdev->options = xf86ReplaceIntOption(pdev->options, "fd", pdev->fd); + + if (pdev->fd < 0) + continue; + + xf86EnableInputDeviceForVTSwitch(pdev); + } +} + +static void activate_vt(void) +{ + enable_drm_devices(); + xf86VTEnter(); + + reopen_input_devices(); + xf86InputEnableVTProbe(); +} + +static void deactivate_vt(void) +{ + disable_drm_devices(); + close_input_devices(); +} + +static void socket_handler(int fd, int ready, void *data) +{ + int ret, opcode; + char buf[64]; + struct weston_launcher_cmd* msg; + + (void)data; + (void)ready; + + ret = recv(fd, buf, sizeof(buf), MSG_DONTWAIT); + + if (ret <= 0) + return; + if (ret < sizeof(*msg)) + return; /* invalid packet? */ + + msg = (void*)buf; + opcode = msg->opcode; + + if (opcode == WESTON_LAUNCHER_ACTIVATE) + activate_vt(); + else if (opcode == WESTON_LAUNCHER_DEACTIVATE) + deactivate_vt(); + else + LogMessage(X_INFO, "weston-launch unknown opcode %i\n", opcode); +} + +static int set_manager_fd(void) +{ + char* fdstr; + int fd; + + if ((fdstr = getenv("WESTON_LAUNCHER_SOCK")) == NULL) { + LogMessage(X_INFO, "weston-launch missing control socket fd\n"); + return -1; + } + + if ((fd = atoi(fdstr)) <= 2) { + LogMessage(X_INFO, "weston-launch invalid control fd %s\n", fdstr); + return -1; + } + + if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) { + LogMessage(X_INFO, "weston-launch cannot set CLOEXEC\n"); + return -1; + } + + weston_launch_fd = fd; + + SetNotifyFd(fd, socket_handler, X_NOTIFY_READ, NULL); + + return 0; +} + +static int set_vt_globals(void) +{ + struct stat st; + + if (fstat(0, &st) < 0) { + LogMessage(X_INFO, "weston-launch cannot stat fd 0\n"); + return -1; + } + + if (!S_ISCHR(st.st_mode) || major(st.st_rdev) != TTY_MAJOR) { + LogMessage(X_INFO, "weston-launch fd 0 is not a tty\n"); + return -1; + } + + xf86Info.vtno = minor(st.st_rdev); + xf86Info.dontVTSwitch = TRUE; + xf86Info.autoVTSwitch = FALSE; + xf86Info.consoleFd = 0; + + serverGeneration = 2; + + return 0; +} + +int weston_launch_init(void) +{ + if (set_manager_fd()) + return -1; + if (set_vt_globals()) + return -1; + + return 0; +} + +static int send_open_request(int fd, const char* path) +{ + struct weston_launcher_open *req; + int len, ret; + + if (path == NULL) { + LogMessage(X_INFO, "weston-launch open NULL\n"); + return -1; + } + + if (strstr(path, "mouse")) + return -1; + + len = sizeof(*req) + strlen(path) + 1; + req = malloc(len); + + if (!req) + return -1; + + req->opcode = WESTON_LAUNCHER_OPEN; + req->flags = O_RDWR; + strcpy(req->path, path); + + ret = send(fd, req, len, 0); + + free(req); + + if (ret < 0) + return -1; + + return 0; +} + +static int recv_open_reply(int fd) +{ + struct msghdr msg; + struct cmsghdr *cmsg; + struct iovec iov; + char control[CMSG_SPACE(sizeof(int))]; + int ret, cmd; + +again: + memset(&msg, 0, sizeof msg); + iov.iov_base = &cmd; + iov.iov_len = sizeof cmd; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = control; + msg.msg_controllen = sizeof control; + + ret = recvmsg(fd, &msg, MSG_CMSG_CLOEXEC); + + if (ret < 0) + return -1; + if (ret < sizeof(int)) { + LogMessage(X_INFO, "weston-launch truncated reply\n"); + return -1; + } + + if (cmd < 0) { + LogMessage(X_INFO, "weston-launch open returns %i\n", cmd); + return cmd; + } + + if (cmd > 0) { + if (cmd == WESTON_LAUNCHER_DEACTIVATE) + deactivate_vt(); + LogMessage(X_INFO, "weston-launch interrupted request\n"); + goto again; + } + + cmsg = CMSG_FIRSTHDR(&msg); + + if (!cmsg) { + LogMessage(X_INFO, "weston-launch got no ancillary data\n"); + return -1; + } + if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { + LogMessage(X_INFO, "weston-launch invalid ancillary data\n"); + return -1; + } + if (cmsg->cmsg_len < sizeof(*cmsg) + sizeof(int)) { + LogMessage(X_INFO, "weston-launch malformed ancillary data\n"); + return -1; + } + + return *((int*)CMSG_DATA(cmsg)); +} + +int weston_launch_open(const char *path) +{ + int rfd, sfd = weston_launch_fd; + + if (send_open_request(sfd, path)) + return -1; + + if ((rfd = recv_open_reply(sfd)) < 0) + return -1; + + fcntl(rfd, F_SETFL, O_NONBLOCK); + + return rfd; +} diff --git a/include/dix-config.h.in b/include/dix-config.h.in index f12df74da..e09ad308b 100644 --- a/include/dix-config.h.in +++ b/include/dix-config.h.in @@ -433,6 +433,9 @@ /* Enable systemd-logind integration */ #undef SYSTEMD_LOGIND 1 +/* Enable weston-launch integration */ +#undef WESTON_LAUNCH 1 + /* Have a monotonic clock from clock_gettime() */ #undef MONOTONIC_CLOCK diff --git a/include/weston-launch.h b/include/weston-launch.h new file mode 100644 index 000000000..371d31eac --- /dev/null +++ b/include/weston-launch.h @@ -0,0 +1,9 @@ +#ifndef WESTON_LAUNCH_H +#define WESTON_LAUNCH_H + +#ifdef WESTON_LAUNCH +int weston_launch_init(void); +int weston_launch_open(const char *path); +#endif + +#endif -- 2.16.1 _______________________________________________ xorg-devel@lists.x.org: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: https://lists.x.org/mailman/listinfo/xorg-devel