sddm: replace sed hacks with proper relibc-backed XAuth + clean Wayland-only build

This commit is contained in:
2026-07-26 15:52:44 +09:00
parent 393754a44d
commit 4f31d4f66a
+166 -40
View File
@@ -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."