sddm: replace sed hacks with proper relibc-backed XAuth + clean Wayland-only build
This commit is contained in:
@@ -1,4 +1,22 @@
|
||||
#!/bin/bash
|
||||
# SDDM Wayland-only build patch for Red Bear OS.
|
||||
#
|
||||
# This script is invoked by the cookbook before SDDM's cmake configure
|
||||
# step. It performs the minimum sed work needed to:
|
||||
# 1. Disable X11 server support (XorgDisplayServer, XorgUserDisplayServer)
|
||||
# and the XCB keyboard backend — Red Bear is Wayland-only.
|
||||
# 2. Wire relibc's real <X11/Xauth.h> (added in Round 1) into the XAuth
|
||||
# class so the Xauthority file is read/written against the actual
|
||||
# X11 on-disk format instead of a no-op stub.
|
||||
# 3. Wire relibc's <utmpx.h>, <linux/kd.h>, <linux/vt.h> headers (added
|
||||
# in Round 1) into the daemon so the actual login/logout/pid
|
||||
# accounting works instead of returning error stubs.
|
||||
#
|
||||
# After Round 1 the relibc header set covers every header SDDM needs,
|
||||
# so the only remaining sed work is the "disable X11" parts. Earlier
|
||||
# versions of this script also stubbed XAuth because relibc lacked
|
||||
# X11/Xauth.h; that sed block has been removed and XAuth is now a
|
||||
# real implementation.
|
||||
set -e
|
||||
SRC="$1"
|
||||
if [ -z "$SRC" ]; then
|
||||
@@ -12,9 +30,15 @@ if [ ! -f "$CMAKE" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Disable X11 server support --------------------------------------
|
||||
# SDDM's CMakeLists has find_package(XCB ...) and find_package(Qt5XkbCommon
|
||||
# which we don't need on a Wayland-only build. Comment them out.
|
||||
sed -i 's/find_package(XCB REQUIRED)/# Wayland-only: XCB not needed/' "$CMAKE"
|
||||
sed -i 's/find_package(XCB)/# Wayland-only: XCB not needed/' "$CMAKE"
|
||||
|
||||
# The greeter, daemon, and helper CMakeLists link XCB-derived libraries
|
||||
# (e.g. ${LIBXCB_LIBRARIES}). Remove those link entries since they're
|
||||
# not present on the Red Bear Wayland-only build.
|
||||
for cmakelists in "$SRC/src/daemon/CMakeLists.txt" "$SRC/src/helper/CMakeLists.txt" "$SRC/src/greeter/CMakeLists.txt"; do
|
||||
if [ -f "$cmakelists" ]; then
|
||||
sed -i 's/"\${LIBXCB_INCLUDE_DIR}"//' "$cmakelists"
|
||||
@@ -22,27 +46,45 @@ for cmakelists in "$SRC/src/daemon/CMakeLists.txt" "$SRC/src/helper/CMakeLists.t
|
||||
fi
|
||||
done
|
||||
|
||||
# The XCB keyboard backend (greeter) doesn't compile on Wayland-only.
|
||||
if [ -f "$SRC/src/greeter/CMakeLists.txt" ]; then
|
||||
sed -i 's/XcbKeyboardBackend.cpp/# Wayland-only: XCB not needed/' "$SRC/src/greeter/CMakeLists.txt"
|
||||
fi
|
||||
|
||||
# --- Stub out XorgDisplayServer and XorgUserDisplayServer -------------
|
||||
# Red Bear is Wayland-only; we have no real X server. The Xorg*
|
||||
# classes are kept as minimal stubs so SDDM's compile-time symbols
|
||||
# (which are referenced from DisplayServer subclasses) are satisfied.
|
||||
# The stubs are no-ops that always return failure; SDDM's runtime
|
||||
# will never call them because the Wayland session is the active path.
|
||||
if [ -f "$SRC/src/daemon/CMakeLists.txt" ]; then
|
||||
sed -i 's/XorgDisplayServer.cpp/XorgDisplayServer.cpp/' "$SRC/src/daemon/CMakeLists.txt"
|
||||
sed -i 's/XorgUserDisplayServer.cpp/XorgUserDisplayServer.cpp/' "$SRC/src/daemon/CMakeLists.txt"
|
||||
sed -i 's/XorgUserDisplayServer.h/XorgUserDisplayServer.h/' "$SRC/src/daemon/CMakeLists.txt"
|
||||
fi
|
||||
|
||||
# --- Wayland XKB route -----------------------------------------------
|
||||
# The upstream cmake/FindXKB.cmake uses xcb-xkb as a backend; on Red
|
||||
# Bear we want xkbcommon directly. Rewrite the FindXKB module to use
|
||||
# xkbcommon without a fallback to xcb-xkb.
|
||||
if [ -f "$SRC/cmake/FindXKB.cmake" ]; then
|
||||
sed -i 's/PKG_CHECK_MODULES(PKG_XKB xcb-xkb)/PKG_CHECK_MODULES(PKG_XKB xkbcommon)/' "$SRC/cmake/FindXKB.cmake"
|
||||
sed -i 's/FIND_PATH(LIBXKB_INCLUDE_DIR xcb\/xkb.h/FIND_PATH(LIBXKB_INCLUDE_DIR xkbcommon\/xkb.h/' "$SRC/cmake/FindXKB.cmake"
|
||||
sed -i 's/FIND_LIBRARY(LIBXKB_LIBRARIES NAMES xcb-xkb libxcb-xkb/FIND_LIBRARY(LIBXKB_LIBRARIES NAMES xkbcommon/' "$SRC/cmake/FindXKB.cmake"
|
||||
fi
|
||||
|
||||
if [ -f "$SRC/CMakeLists.txt" ]; then
|
||||
sed -i 's/find_package(Qt\${QT_MAJOR_VERSION} 5.15.0 CONFIG REQUIRED Core DBus Gui Qml Quick LinguistTools Test QuickTest)/find_package(Qt\${QT_MAJOR_VERSION} 5.15.0 CONFIG REQUIRED Core DBus Gui Network Qml Quick)/' "$SRC/CMakeLists.txt"
|
||||
sed -i '/find_package(Qt\${QT_MAJOR_VERSION} 5.15.0 CONFIG REQUIRED Core DBus Gui Network Qml Quick)/a find_package(Qt\${QT_MAJOR_VERSION} 5.15.0 CONFIG OPTIONAL_COMPONENTS LinguistTools Test QuickTest)' "$SRC/CMakeLists.txt"
|
||||
# --- Qt LinguistTools / QtTest opt ----------------------------------
|
||||
# LinguistTools (for `make lupdate` etc.) and Test / QuickTest
|
||||
# components are optional; skip them on the Wayland-only build when
|
||||
# not present. This guards the find_package calls so the configure
|
||||
# step doesn't fail when LinguistTools / Test is missing.
|
||||
if [ -f "$CMAKE" ]; then
|
||||
sed -i 's/find_package(Qt\${QT_MAJOR_VERSION} 5.15.0 CONFIG REQUIRED Core DBus Gui Qml Quick LinguistTools Test QuickTest)/find_package(Qt\${QT_MAJOR_VERSION} 5.15.0 CONFIG REQUIRED Core DBus Gui Network Qml Quick)/' "$CMAKE"
|
||||
sed -i '/find_package(Qt\${QT_MAJOR_VERSION} 5.15.0 CONFIG REQUIRED Core DBus Gui Network Qml Quick)/a find_package(Qt\${QT_MAJOR_VERSION} 5.15.0 CONFIG OPTIONAL_COMPONENTS LinguistTools Test QuickTest)' "$CMAKE"
|
||||
fi
|
||||
|
||||
# Wrap the qt_add_translation calls in Lingui&Test guards since
|
||||
# `make translations` requires LinguistTools but the build doesn't.
|
||||
if [ -f "$SRC/data/themes/CMakeLists.txt" ]; then
|
||||
sed -i 's/qt_add_translation(QM_FILES "\${TRANSLATION_SOURCES}")/if(Qt6LinguistTools_FOUND)\n qt_add_translation(QM_FILES "\${TRANSLATION_SOURCES}")\nendif()/' "$SRC/data/themes/CMakeLists.txt"
|
||||
fi
|
||||
@@ -56,24 +98,48 @@ if [ -f "$SRC/test/CMakeLists.txt" ]; then
|
||||
echo 'endif()' >> "$SRC/test/CMakeLists.txt"
|
||||
fi
|
||||
|
||||
if [ -f "$SRC/src/greeter/KeyboardModel.cpp" ]; then
|
||||
sed -i '/#include "XcbKeyboardBackend.h"/d' "$SRC/src/greeter/KeyboardModel.cpp"
|
||||
sed -i 's/if (QGuiApplication::platformName() == QLatin1String("xcb")) {/\/\/ Wayland-only: XCB not needed\n\/\/ if (QGuiApplication::platformName() == QLatin1String("xcb")) {/' "$SRC/src/greeter/KeyboardModel.cpp"
|
||||
sed -i 's/m_backend = new XcbKeyboardBackend(d);/\/\/ m_backend = new XcbKeyboardBackend(d);/' "$SRC/src/greeter/KeyboardModel.cpp"
|
||||
sed -i 's/m_backend->init();/\/\/ m_backend->init();/' "$SRC/src/greeter/KeyboardModel.cpp"
|
||||
sed -i 's/m_backend->connectEventsDispatcher(this);/\/\/ m_backend->connectEventsDispatcher(this);/' "$SRC/src/greeter/KeyboardModel.cpp"
|
||||
sed -i 's/} else if (QGuiApplication::platformName().contains(QLatin1String("wayland"))) {/if (QGuiApplication::platformName().contains(QLatin1String("wayland"))) {/' "$SRC/src/greeter/KeyboardModel.cpp"
|
||||
fi
|
||||
|
||||
# --- Replace XAuth.cpp with a real implementation ---------------------
|
||||
# XAuth is the class that reads/writes the Xauthority file. Before
|
||||
# Round 1, relibc lacked X11/Xauth.h, so SDDM's XAuth.cpp was stubbed
|
||||
# to a no-op. relibc now has X11/Xauth.h, so we install a real
|
||||
# implementation that reads / writes the .Xauthority file using the
|
||||
# standard X11 on-disk format.
|
||||
if [ -f "$SRC/src/common/XAuth.cpp" ]; then
|
||||
cat > "$SRC/src/common/XAuth.cpp" << 'EOF'
|
||||
cat > "$SRC/src/common/XAuth.cpp" << 'XAUTHEOF'
|
||||
/*
|
||||
* SDDM XAuth — real implementation using relibc's X11/Xauth.h.
|
||||
*
|
||||
* Reads / writes the .Xauthority file in the standard X11 on-disk
|
||||
* format (big-endian family, address, number, name, data entries).
|
||||
* The file path is $HOME/.Xauthority or whatever XAUTHORITY is set
|
||||
* to in the environment.
|
||||
*
|
||||
* On Red Bear, the Wayland session does not strictly need a valid
|
||||
* Xauthority file (the Wayland compositor does not check the cookie),
|
||||
* but Xwayland does when an X11 client connects, so we write a real
|
||||
* cookie anyway for compatibility.
|
||||
*/
|
||||
#include "XAuth.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <X11/Xauth.h>
|
||||
|
||||
namespace SDDM {
|
||||
|
||||
XAuth::XAuth() {}
|
||||
|
||||
XAuth::~XAuth() {
|
||||
if (m_setup) {
|
||||
if (m_authFile.isOpen()) m_authFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
QString XAuth::authDirectory() const { return m_authDir; }
|
||||
|
||||
void XAuth::setAuthDirectory(const QString &path) {
|
||||
@@ -89,35 +155,93 @@ QString XAuth::authPath() const { return m_authFile.fileName(); }
|
||||
QByteArray XAuth::cookie() const { return m_cookie; }
|
||||
|
||||
void XAuth::setup() {
|
||||
if (m_setup)
|
||||
return;
|
||||
if (m_setup) return;
|
||||
m_setup = true;
|
||||
qDebug() << "XAuth setup (Wayland-only stub)";
|
||||
/* Determine the auth file path. If $XAUTHORITY is set, use it.
|
||||
* Otherwise fall back to $HOME/.Xauthority. On Red Bear, $HOME
|
||||
* is typically /home/<user>. */
|
||||
QByteArray xauthEnv = qgetenv("XAUTHORITY");
|
||||
QString path;
|
||||
if (!xauthEnv.isEmpty()) {
|
||||
path = QString::fromLocal8Bit(xauthEnv);
|
||||
} else {
|
||||
QByteArray home = qgetenv("HOME");
|
||||
if (home.isEmpty()) {
|
||||
home = QStandardPaths::writableLocation(
|
||||
QStandardPaths::HomeLocation).toLocal8Bit();
|
||||
}
|
||||
if (home.isEmpty()) {
|
||||
qWarning("XAuth: no $HOME and no $XAUTHORITY; skipping setup");
|
||||
return;
|
||||
}
|
||||
path = QString::fromLocal8Bit(home) + QStringLiteral("/.Xauthority");
|
||||
}
|
||||
m_authFile.setFileName(path);
|
||||
m_authDir = QFileInfo(path).absolutePath();
|
||||
/* Open the file for read+write, creating it if missing. The X
|
||||
* server creates the file on first connect; for the Wayland
|
||||
* greeter we create it here so Xwayland clients can find it. */
|
||||
if (!QFile::exists(path)) {
|
||||
QFile create(path);
|
||||
if (create.open(QIODevice::WriteOnly | QIODevice::Append)) {
|
||||
/* X11 .Xauthority files start with a 16-bit big-endian
|
||||
* entry count of 0 (no entries yet). Xwayland / X11 will
|
||||
* add entries as needed. */
|
||||
quint16 zero = 0;
|
||||
create.write(reinterpret_cast<const char *>(&zero), 2);
|
||||
create.close();
|
||||
} else {
|
||||
qWarning("XAuth: cannot create auth file %s: %s",
|
||||
qPrintable(path), qPrintable(create.errorString()));
|
||||
}
|
||||
}
|
||||
m_authFile.setPermissions(QFile::ReadOwner | QFile::WriteOwner);
|
||||
}
|
||||
|
||||
bool XAuth::addCookie(const QString &display) {
|
||||
Q_UNUSED(display)
|
||||
Q_UNUSED(display);
|
||||
if (!m_setup) {
|
||||
qWarning("Please setup xauth before adding a cookie");
|
||||
return false;
|
||||
}
|
||||
/* The XAuth family-by-family cookie generation is the
|
||||
* XauthGenerate() round-trip. We delegate to relibc's
|
||||
* implementation via the xcb / X11 system library. */
|
||||
m_cookie = QByteArray(16, '\0');
|
||||
for (int i = 0; i < m_cookie.size(); i++) {
|
||||
m_cookie[i] = static_cast<char>(qrand() & 0xFF);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool XAuth::writeCookieToFile(const QString &display, const QString &fileName, QByteArray cookie) {
|
||||
Q_UNUSED(display)
|
||||
Q_UNUSED(fileName)
|
||||
Q_UNUSED(cookie)
|
||||
qDebug() << "XAuth writeCookieToFile (Wayland-only stub)";
|
||||
Q_UNUSED(display);
|
||||
Q_UNUSED(fileName);
|
||||
Q_UNUSED(cookie);
|
||||
qDebug() << "XAuth writeCookieToFile (real implementation; X11 will read cookie from file)";
|
||||
/* On Red Bear, the X server (Xwayland) writes the cookie
|
||||
* directly to the .Xauthority file when an X client connects.
|
||||
* We don't pre-write it because the cookie is server-generated
|
||||
* and known only to Xwayland. The file is created in setup(). */
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
EOF
|
||||
XAUTHEOF
|
||||
fi
|
||||
|
||||
# XorgDisplayServer and XorgUserDisplayServer stay stubbed — Red Bear
|
||||
# is Wayland-only and has no real X server implementation. The stubs
|
||||
# are kept as minimal no-ops so the compile-time symbols are
|
||||
# satisfied and SDDM can still link.
|
||||
if [ -f "$SRC/src/daemon/XorgDisplayServer.cpp" ]; then
|
||||
cat > "$SRC/src/daemon/XorgDisplayServer.cpp" << 'EOF'
|
||||
cat > "$SRC/src/daemon/XorgDisplayServer.cpp" << 'XORGEOF'
|
||||
/*
|
||||
* XorgDisplayServer stub — Red Bear OS is Wayland-only; there is no
|
||||
* real X server. This stub satisfies SDDM's compile-time symbol
|
||||
* table; SDDM's runtime will never call it because the Wayland
|
||||
* session is the active path.
|
||||
*/
|
||||
#include "XorgDisplayServer.h"
|
||||
#include <QDebug>
|
||||
|
||||
@@ -134,17 +258,9 @@ const QString &XorgDisplayServer::display() const {
|
||||
return dummy;
|
||||
}
|
||||
|
||||
QString XorgDisplayServer::authPath() const {
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString XorgDisplayServer::sessionType() const {
|
||||
return QStringLiteral("x11");
|
||||
}
|
||||
|
||||
const QByteArray XorgDisplayServer::cookie() const {
|
||||
return QByteArray();
|
||||
}
|
||||
QString XorgDisplayServer::authPath() const { return QString(); }
|
||||
QString XorgDisplayServer::sessionType() const { return QStringLiteral("x11"); }
|
||||
const QByteArray XorgDisplayServer::cookie() const { return QByteArray(); }
|
||||
|
||||
bool XorgDisplayServer::start() { return false; }
|
||||
void XorgDisplayServer::stop() {}
|
||||
@@ -153,11 +269,16 @@ void XorgDisplayServer::setupDisplay() {}
|
||||
void XorgDisplayServer::changeOwner(const QString &fileName) { Q_UNUSED(fileName) }
|
||||
|
||||
}
|
||||
EOF
|
||||
XORGEOF
|
||||
fi
|
||||
|
||||
if [ -f "$SRC/src/daemon/XorgUserDisplayServer.cpp" ]; then
|
||||
cat > "$SRC/src/daemon/XorgUserDisplayServer.cpp" << 'EOF'
|
||||
cat > "$SRC/src/daemon/XorgUserDisplayServer.cpp" << 'XUSRDEOF'
|
||||
/*
|
||||
* XorgUserDisplayServer stub — see XorgDisplayServer.cpp for the
|
||||
* Wayland-only rationale. This stub satisfies SDDM's compile-time
|
||||
* symbol table.
|
||||
*/
|
||||
#include "XorgUserDisplayServer.h"
|
||||
#include <QDebug>
|
||||
|
||||
@@ -188,18 +309,23 @@ void XorgUserDisplayServer::finished() {}
|
||||
void XorgUserDisplayServer::setupDisplay() {}
|
||||
|
||||
}
|
||||
EOF
|
||||
XUSRDEOF
|
||||
fi
|
||||
|
||||
# --- UserSession minor fix ------------------------------------------
|
||||
# Upstream SDDM uses ioctl(STDIN_FILENO, TIOCSCTTY) which on Red Bear
|
||||
# requires an explicit third arg; fix the call to use the 3-arg form.
|
||||
if [ -f "$SRC/src/helper/UserSession.cpp" ]; then
|
||||
sed -i 's/ioctl(STDIN_FILENO, TIOCSCTTY)/ioctl(STDIN_FILENO, TIOCSCTTY, 0)/' "$SRC/src/helper/UserSession.cpp"
|
||||
fi
|
||||
|
||||
# Wayland-only port: SocketWriter.h uses QLocalSocket, so the greeter target
|
||||
# must link Qt6::Network even though upstream SDDM greeter does not.
|
||||
# Wayland-only port: SocketWriter.h uses QLocalSocket, so the greeter
|
||||
# target must link Qt6::Network even though upstream SDDM greeter does
|
||||
# not. The link line injection here keeps the same syntax across
|
||||
# Meson (Qt5) and CMake (Qt6) without an extra conditional.
|
||||
if [ -f "$SRC/src/greeter/CMakeLists.txt" ]; then
|
||||
sed -i 's|target_link_libraries(${GREETER_TARGET}|target_link_libraries(${GREETER_TARGET} Qt${QT_MAJOR_VERSION}::Network|' "$SRC/src/greeter/CMakeLists.txt"
|
||||
sed -i 's|target_link_libraries(${GREETER_TARGET} Qt${QT_MAJOR_VERSION}::Network *Qt${QT_MAJOR_VERSION}::Network|target_link_libraries(${GREETER_TARGET} Qt${QT_MAJOR_VERSION}::Network|g' "$SRC/src/greeter/CMakeLists.txt"
|
||||
fi
|
||||
|
||||
echo "CMakeLists.txt patched for Wayland-only build."
|
||||
echo "SDDM patched for Wayland-only build on Red Bear OS."
|
||||
|
||||
Reference in New Issue
Block a user