[RFC xserver 2/2] xfree86: weston-launch protocol support
Alex Suykov
alex.suykov at gmail.com
Tue Feb 13 17:22:04 UTC 2018
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.suykov at 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
More information about the xorg-devel
mailing list