From 6de8136907df1b489de43d431170da4e8fca6379 Mon Sep 17 00:00:00 2001 From: Tautvis Date: Wed, 3 Sep 2025 18:51:08 +0300 Subject: [PATCH] Patch 1/5 xfree86: libseat support, the seatd-libseat.{c,h} code This is initial patch for libseat. Technicaly almost verbatim code (with style changes) from Devuan xorg server moved to os-support/shared directory as it can support other oses than linux. The original repository: https://git.devuan.org/devuan/xorg-server.git The patch between fc24510f17e89a5bbac1065abab758a4d0c42634 and 6bf62381d0a1fb54226a10f9d0e6b03aff12f3aa Co-Authored-By: Mark Hindley Co-Authored-By: Ralph Ronnquist Signed-off-By: Tautvis --- hw/xfree86/common/seatd-libseat.h | 49 +++ hw/xfree86/os-support/shared/seatd-libseat.c | 394 +++++++++++++++++++ 2 files changed, 443 insertions(+) create mode 100644 hw/xfree86/common/seatd-libseat.h create mode 100644 hw/xfree86/os-support/shared/seatd-libseat.c diff --git a/hw/xfree86/common/seatd-libseat.h b/hw/xfree86/common/seatd-libseat.h new file mode 100644 index 000000000..cbc0d2a9e --- /dev/null +++ b/hw/xfree86/common/seatd-libseat.h @@ -0,0 +1,49 @@ +/* + * Copyright © 2022-2024 Mark Hindley, Ralph Ronnquist. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: Mark Hindley + * Ralph Ronnquist + */ + +#ifndef SEATD_LIBSEAT_H +#define SEATD_LIBSEAT_H + +#ifdef SEATD_LIBSEAT +#include +extern int seatd_libseat_init(void); +extern void seatd_libseat_fini(void); +extern int seatd_libseat_open_graphics(const char *path); +extern void seatd_libseat_open_device(InputInfoPtr p,int *fd,Bool *paus); +extern void seatd_libseat_close_device(InputInfoPtr p); +extern int seatd_libseat_switch_session(int session); +extern Bool seatd_libseat_controls_session(void); +#else +#define seatd_libseat_init() +#define seatd_libseat_fini() +#define seatd_libseat_open_graphics(path) -1 +#define seatd_libseat_open_device(p,x,y) +#define seatd_libseat_close_device(p) +#define seatd_libseat_switch_session(int) -1 +#define seatd_libseat_controls_session() FALSE +#endif + +#endif diff --git a/hw/xfree86/os-support/shared/seatd-libseat.c b/hw/xfree86/os-support/shared/seatd-libseat.c new file mode 100644 index 000000000..4a48c7d4b --- /dev/null +++ b/hw/xfree86/os-support/shared/seatd-libseat.c @@ -0,0 +1,394 @@ +/* + * Copyright © 2022-2024 Mark Hindley, Ralph Ronnquist. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: Mark Hindley + * Ralph Ronnquist + */ + +#ifdef HAVE_XORG_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "os.h" +#include "linux.h" +#include "xf86.h" +#include "xf86platformBus.h" +#include "xf86Xinput.h" +#include "xf86Priv.h" +#include "globals.h" +#include "seatd-libseat.h" + +/* ============ libseat client adapter ====================== */ + +struct libseat_info { + char *session; + Bool active; + Bool vt_active; + /* + * This pointer gets initialised to the actual libseat client instance + * provided by libseat_open_seat. + */ + struct libseat *client; + int graphics_id; +}; +static struct libseat_info seat_info; + +/* + * The seat has been enabled, and is now valid for use. Re-open all + * seat devices to ensure that they are operational, as existing fds + * may have had their functionality blocked or revoked. + */ +static void +enable_seat(struct libseat *seat, void *userdata) +{ + InputInfoPtr pInfo; + (void) userdata; + LogMessage(X_INFO, "seatd_libseat enable\n"); + seat_info.active = TRUE; + seat_info.vt_active = TRUE; + + xf86VTEnter(); + /* Reactivate all input devices */ + for (pInfo = xf86InputDevs; pInfo; pInfo = pInfo->next) + if (pInfo->flags & XI86_SERVER_FD){ + if (xf86CheckIntOption(pInfo->options, "libseat_id", -1) > 0){ + int fd = -1, paused = FALSE; + seatd_libseat_open_device(pInfo, &fd, &paused); + xf86EnableInputDeviceForVTSwitch(pInfo); + } + } + xf86InputEnableVTProbe(); /* Add any paused input devices */ + xf86platformVTProbe(); /* Probe for outputs */ +} + +/* + * The seat has been disabled. This event signals that the application + * is going to lose its seat access. The event *must* be acknowledged + * with libseat_disable_seat shortly after receiving this event. + * + * If the recepient fails to acknowledge the event in time, seat + * devices may be forcibly revoked by the seat provider. + */ +static void +disable_seat(struct libseat *seat, void *userdata) +{ + (void) userdata; + LogMessage(X_INFO, "seatd_libseat disable\n"); + xf86VTLeave(); + seat_info.vt_active = FALSE; + if (libseat_disable_seat(seat)) { + LogMessage(X_ERROR, "seatd_libseat disable failed: %d\n", errno); + } +} + +/* + * Callbacks for handling the libseat events. + */ +static struct +libseat_seat_listener client_callbacks = { + .enable_seat = enable_seat, + .disable_seat = disable_seat, +}; + +/* + * Check libseat is initialised and active. + */ +static Bool +libseat_active(void) +{ + if (!seat_info.client) { + LogMessageVerb(X_DEBUG, 5, "seatd_libseat not initialised!\n"); + return FALSE; + } + if (!seat_info.active) { + LogMessage(X_DEBUG, "seatd_libseat not active\n"); + return FALSE; + } + return TRUE; +} + +/* + * Handle libseat events + */ +static int +libseat_handle_events(int timeout) +{ + int ret; + + while ((ret = libseat_dispatch(seat_info.client, timeout)) > 0) + LogMessage(X_INFO, "seatd_libseat handled %i events\n", ret); + if (ret == -1) { + LogMessage(X_ERROR, "libseat_dispatch() failed: %s\n", strerror(errno)); + return -1; + } + return ret; +} + +static void +event_handler(int fd, int ready, void *data) +{ + LogMessage(X_INFO, "seatd_libseat event handler\n"); + libseat_handle_events(0); +} + +/* + * Handle libseat logging. + */ +static void +log_libseat(enum libseat_log_level level, const char *fmt, va_list args) +{ + MessageType xmt; + size_t xfmt_size = strlen(fmt) + 2; + char *xfmt; + + xfmt = malloc(xfmt_size); + if (xfmt == NULL) + return; + snprintf(xfmt, xfmt_size, "%s\n", fmt); + + switch (level) { + case LIBSEAT_LOG_LEVEL_INFO: + xmt = X_INFO; + break; + case LIBSEAT_LOG_LEVEL_ERROR: + xmt = X_ERROR; + break; + default: + xmt = X_DEBUG; + } + LogVMessageVerb(xmt, 0, xfmt, args); + + free(xfmt); +} + +/* ============== seatd-libseat.h API functions ============= */ + +/* + * Initialise the libseat client. + * + * Returns: + * 0 if all ok + * 1 if not possible + * -EPERM (-1) if it was already initialised + * -EPIPE (-32) if the seat opening failed. + */ +int +seatd_libseat_init(void) +{ + if (!ServerIsNotSeat0() && xf86HasTTYs() && linux_parse_vt_settings(TRUE) && !linux_get_keeptty()) { + LogMessage(X_INFO, + "seat-libseat: libseat integration requires -keeptty which " + "was not provided, disabling\n"); + return 1; + } + + libseat_set_log_level(LIBSEAT_LOG_LEVEL_DEBUG); + libseat_set_log_handler(log_libseat); + LogMessage(X_INFO, "seatd_libseat init\n"); + if (libseat_active()) { + LogMessage(X_ERROR, "seatd_libseat already initialised\n"); + return -EPERM; + } + seat_info.graphics_id = -1; + seat_info.client = libseat_open_seat(&client_callbacks, NULL); + if (!seat_info.client) { + LogMessage(X_ERROR, "Cannot set up seatd_libseat client\n"); + return -EPIPE; + } + SetNotifyFd(libseat_get_fd(seat_info.client), event_handler, X_NOTIFY_READ, NULL); + + if (libseat_handle_events(100) < 0) { + libseat_close_seat(seat_info.client); + return -EPIPE; + } + LogMessage(X_INFO, "seatd_libseat client activated\n"); + return 0; +} + +/* + * Shutdown the libseat client. + */ +void +seatd_libseat_fini(void) +{ + if (seat_info.client) { + LogMessage(X_INFO, "seatd_libseat finish\n"); + libseat_close_seat(seat_info.client); + } + seat_info.graphics_id = -1; + seat_info.active = FALSE; + seat_info.client = NULL; +} + +/* + * Open the graphics device + * + * Return + * file descriptor (>=0) if all is ok. + * -EPERM (-1) if the libseat client is not activated + * -EAGAIN (-11) if the VT is not active + * -errno from libseat_open_device if device access failed + */ +int +seatd_libseat_open_graphics(const char *path) +{ + int fd, id; + + if (!libseat_active()) { + return -EPERM; + } + LogMessage(X_INFO, "seatd_libseat try open graphics %s\n", path); + if ((id = libseat_open_device(seat_info.client, path, &fd)) == -1) { + fd = -errno; + LogMessage(X_ERROR, "seatd_libseat open graphics %s (%d) failed: %d\n", + path, id, fd); + } + else { + LogMessage(X_INFO, "seatd_libseat opened graphics: %s (%d:%d)\n", path, + id, fd); + } + seat_info.graphics_id = id; + return fd; +} + +/* + * Find duplicate devices with same major:minor number and assigned + * "libseat_id" and, if any, return its file descriptor. + */ +static int +check_duplicate_device(int maj, int min) { + + InputInfoPtr pInfo; + + for (pInfo = xf86InputDevs; pInfo; pInfo = pInfo->next) { + if (pInfo->major == maj && pInfo->minor == min && + xf86CheckIntOption(pInfo->options, "libseat_id", -1) >= 0) { + return pInfo->fd; + } + } + return -1; +} + +/* + * Open an input device. + * + * The function sets the p->options "libseat_id" for the device when + * successful. + */ +void +seatd_libseat_open_device(InputInfoPtr p, int *pfd, Bool *paused) +{ + int id, fd; + char *path = xf86CheckStrOption(p->options, "Device", NULL); + + if (!libseat_active()) { + return; + } + if (!seat_info.vt_active) { + *pfd = -2; /* Invalid, but not -1. See xf86NewInputDevice() */ + *paused = TRUE; + LogMessage(X_INFO, "seatd_libseat paused %s\n", path); + return; + } + fd = check_duplicate_device(p->major,p->minor); + if (fd < 0) { + LogMessage(X_INFO, "seatd_libseat try open %s\n", path); + if ((id = libseat_open_device(seat_info.client, path, &fd)) == -1) { + fd = -errno; + LogMessage(X_ERROR, "seatd_libseat open %s (%d) failed: %d\n", + path, id, fd); + return; + } + } + else { + LogMessage(X_INFO, "seatd_libseat reuse %d for %s\n", fd, path); + } + p->flags |= XI86_SERVER_FD; + p->fd = fd; + p->options = xf86ReplaceIntOption(p->options, "fd", fd); + p->options = xf86ReplaceIntOption(p->options, "libseat_id", id); + LogMessage(X_INFO, "seatd_libseat opened %s (%d:%d)\n", path, id, fd); +} + +/* + * Release an input device. + */ +void +seatd_libseat_close_device(InputInfoPtr p) +{ + char *path = xf86CheckStrOption(p->options, "Device", NULL); + int fd = xf86CheckIntOption(p->options, "fd", -1); + int id = xf86CheckIntOption(p->options, "libseat_id", -1); + + if (!libseat_active()) + return; + LogMessage(X_INFO, "seatd_libseat try close %s (%d:%d)\n", path, id, fd); + if (fd < 0) { + LogMessage(X_ERROR, "seatd_libseat device not open (%s)\n", path); + return; + } + if (id < 0) { + LogMessage(X_ERROR, "seatd_libseat no libseat ID\n"); + return; + } + if (libseat_close_device(seat_info.client, id)) { + LogMessage(X_ERROR, "seatd_libseat close failed %d\n", -errno); + } + else { + close(fd); + p->fd = -1; + p->options = xf86ReplaceIntOption(p->options, "fd", -1); + } +} + +/* + * Libseat controls session + */ + +Bool +seatd_libseat_controls_session(void){ + return libseat_active(); +} + +/* + * Switch VT + */ +int +seatd_libseat_switch_session(int session) +{ + int ret=0; + + LogMessage(X_INFO, "seatd_libseat switch VT %d\n", session); + if ((ret = libseat_switch_session(seat_info.client, session)) < 0) { + LogMessage(X_ERROR, "seatd_libseat switch VT failed with %d\n", -errno); + goto ret; + } + ret: + return ret; +}