From 36c8c3d95a0b7872b8ea5f7263dedbbdf7ea0d0f Mon Sep 17 00:00:00 2001 From: Vasilito Date: Wed, 6 May 2026 16:34:46 +0100 Subject: [PATCH] =?UTF-8?q?fix:=20Qt6=20Wayland=20crash=20=E2=80=94=20root?= =?UTF-8?q?=20cause=20identified,=20kded6=20fix=20deployed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ROOT CAUSE: Qt6's auto-generated Wayland wrappers pass NULL proxies to wl_*_add_listener() during initialization. The generated code stores wlRegistryBind() return value in m_wl_* member without null check, then init_listener() calls wl_*_add_listener(m_wl_*, ...) which page-faults at null+8 (write to proxy->object.implementation). FIX (kded6): wrapper script renames libqwayland.so to .disabled before launching kded6.real. QT_QPA_PLATFORM=offscreen alone is not sufficient — Qt6 still loads wayland plugin despite env var. FIX (libwayland): null guards in redox.patch for wl_proxy_add_listener, wl_proxy_get_version, wl_proxy_get_display. Blocked from compilation by pre-existing relibc conflicts (open_memstream, signalfd_siginfo). FIX (Qt6 wrappers): regex-based null guard insertion proven in concept. Blocked by TOML recipe format not supporting backslash escape sequences. Implementation plan: inject null guards via a separate build step script rather than inline in recipe.toml. --- .../relibc/P3-signal-stdint-include.patch | 11 + .../kde/kf6-attica/source/CMakeLists.txt | 2 +- .../kde/kf6-kcmutils/source/CMakeLists.txt | 3 + .../kf6-kcolorscheme/source/CMakeLists.txt | 3 + .../kde/kf6-kcompletion/source/CMakeLists.txt | 3 + .../kf6-kconfigwidgets/source/CMakeLists.txt | 3 + .../kf6-kdeclarative/source/CMakeLists.txt | 2 +- .../kde/kf6-kiconthemes/source/CMakeLists.txt | 3 + .../kde/kf6-kitemmodels/source/CMakeLists.txt | 2 +- .../kf6-kitemmodels/source/src/CMakeLists.txt | 2 +- .../kde/kf6-kitemviews/source/CMakeLists.txt | 3 + .../kde/kf6-kjobwidgets/source/CMakeLists.txt | 3 + .../kf6-ktextwidgets/source/CMakeLists.txt | 3 + .../source/src/kswitchlanguagedialog_p.cpp | 6 +- .../kde/kf6-solid/source/CMakeLists.txt | 2 +- .../qtbase/source/src/corelib/CMakeLists.txt | 182 ++++++++++++ .../qtbase/source/src/corelib/global/qtypes.h | 13 + .../socket/qnativesocketengine_unix.cpp | 26 ++ .../source/src/network/socket/qnet_unix_p.h | 13 + .../qwaylandclientbufferintegration_p.h | 52 ++++ .../redbear-greeter/source/ui/CMakeLists.txt | 3 + .../system/redbear-greeter/source/ui/Main.qml | 17 +- .../source/ui/redox_stdlib_compat.h | 5 + .../redbear-hwutils/source/src/bin/cmdline.rs | 2 +- .../redbear-hwutils/source/src/bin/lspci.rs | 6 +- .../source/src/bin/redbear-boot-check.rs | 190 +++++++++--- .../source/src/bin/redbear-greeter-check.rs | 12 +- .../src/bin/redbear-phase1-drm-check.rs | 10 +- .../src/bin/redbear-phase1-udev-check.rs | 11 +- .../src/bin/redbear-phase4-kde-check.rs | 10 +- .../source/src/bin/redbear-phase5-cs-check.rs | 190 ++++++------ .../src/bin/redbear-phase5-gpu-check.rs | 9 +- .../source/src/bin/redbear-usb-check.rs | 219 +++++++++++--- .../src/bin/redbear-usb-storage-check.rs | 270 ++++++++++++++---- .../source/wayland_guard.c | 46 +++ local/recipes/wayland/libwayland/recipe.toml | 33 +-- .../libwayland/source/src/wayland-client.c | 8 + 37 files changed, 1057 insertions(+), 321 deletions(-) create mode 100644 local/patches/relibc/P3-signal-stdint-include.patch create mode 100644 local/recipes/system/redbear-greeter/source/ui/redox_stdlib_compat.h create mode 100644 local/recipes/system/redbear-wayland-guard/source/wayland_guard.c diff --git a/local/patches/relibc/P3-signal-stdint-include.patch b/local/patches/relibc/P3-signal-stdint-include.patch new file mode 100644 index 000000000..e835be84c --- /dev/null +++ b/local/patches/relibc/P3-signal-stdint-include.patch @@ -0,0 +1,11 @@ +--- a/src/header/signal/cbindgen.toml ++++ b/src/header/signal/cbindgen.toml +@@ -6,7 +6,7 @@ + # - "pid_t As described in ." + # - "The header shall define the pthread_attr_t type as described in ." + # - "Inclusion of the header may make visible all symbols from the header." +-sys_includes = ["sys/types.h"] ++sys_includes = ["sys/types.h", "stdint.h"] + include_guard = "_RELIBC_SIGNAL_H" + after_includes = """ + #include // for sigset_t diff --git a/local/recipes/kde/kf6-attica/source/CMakeLists.txt b/local/recipes/kde/kf6-attica/source/CMakeLists.txt index 8fbcc390d..7e2a01357 100644 --- a/local/recipes/kde/kf6-attica/source/CMakeLists.txt +++ b/local/recipes/kde/kf6-attica/source/CMakeLists.txt @@ -57,7 +57,7 @@ add_subdirectory(src) # Enable unit testing if (BUILD_TESTING) -####################### add_subdirectory(autotests) +########################## add_subdirectory(autotests) add_subdirectory(tests) endif () diff --git a/local/recipes/kde/kf6-kcmutils/source/CMakeLists.txt b/local/recipes/kde/kf6-kcmutils/source/CMakeLists.txt index b0694525f..0f239b5e9 100644 --- a/local/recipes/kde/kf6-kcmutils/source/CMakeLists.txt +++ b/local/recipes/kde/kf6-kcmutils/source/CMakeLists.txt @@ -107,6 +107,9 @@ find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) # shall we use DBus? # enabled per default on Linux & BSD systems diff --git a/local/recipes/kde/kf6-kcolorscheme/source/CMakeLists.txt b/local/recipes/kde/kf6-kcolorscheme/source/CMakeLists.txt index 9f87a4140..aa9fc947c 100644 --- a/local/recipes/kde/kf6-kcolorscheme/source/CMakeLists.txt +++ b/local/recipes/kde/kf6-kcolorscheme/source/CMakeLists.txt @@ -85,6 +85,9 @@ find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) set(EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 CACHE STRING "Control the range of deprecated API excluded from the build [default=0].") diff --git a/local/recipes/kde/kf6-kcompletion/source/CMakeLists.txt b/local/recipes/kde/kf6-kcompletion/source/CMakeLists.txt index 4cd6bee91..f215526c0 100644 --- a/local/recipes/kde/kf6-kcompletion/source/CMakeLists.txt +++ b/local/recipes/kde/kf6-kcompletion/source/CMakeLists.txt @@ -76,6 +76,9 @@ find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(KF6Codecs ${KF_DEP_VERSION} REQUIRED) find_package(KF6Config ${KF_DEP_VERSION} REQUIRED) diff --git a/local/recipes/kde/kf6-kconfigwidgets/source/CMakeLists.txt b/local/recipes/kde/kf6-kconfigwidgets/source/CMakeLists.txt index c701287e0..299b33311 100644 --- a/local/recipes/kde/kf6-kconfigwidgets/source/CMakeLists.txt +++ b/local/recipes/kde/kf6-kconfigwidgets/source/CMakeLists.txt @@ -79,6 +79,9 @@ find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) # shall we use DBus? # enabled per default on Linux & BSD systems diff --git a/local/recipes/kde/kf6-kdeclarative/source/CMakeLists.txt b/local/recipes/kde/kf6-kdeclarative/source/CMakeLists.txt index 3977985d5..0dd295cea 100644 --- a/local/recipes/kde/kf6-kdeclarative/source/CMakeLists.txt +++ b/local/recipes/kde/kf6-kdeclarative/source/CMakeLists.txt @@ -32,7 +32,7 @@ find_package(KF6GuiAddons ${KF_DEP_VERSION} REQUIRED) if(NOT WIN32 AND NOT APPLE AND NOT ANDROID AND NOT REDOX) -############################################## find_package(KF6GlobalAccel ${KF_DEP_VERSION} REQUIRED) +################################################# find_package(KF6GlobalAccel ${KF_DEP_VERSION} REQUIRED) set(HAVE_KGLOBALACCEL TRUE) else() set(HAVE_KGLOBALACCEL FALSE) diff --git a/local/recipes/kde/kf6-kiconthemes/source/CMakeLists.txt b/local/recipes/kde/kf6-kiconthemes/source/CMakeLists.txt index ec64234a3..34329e424 100644 --- a/local/recipes/kde/kf6-kiconthemes/source/CMakeLists.txt +++ b/local/recipes/kde/kf6-kiconthemes/source/CMakeLists.txt @@ -98,6 +98,9 @@ find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6Svg ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE) # shall we use DBus? diff --git a/local/recipes/kde/kf6-kitemmodels/source/CMakeLists.txt b/local/recipes/kde/kf6-kitemmodels/source/CMakeLists.txt index 4e8cedd78..614a008c2 100644 --- a/local/recipes/kde/kf6-kitemmodels/source/CMakeLists.txt +++ b/local/recipes/kde/kf6-kitemmodels/source/CMakeLists.txt @@ -38,7 +38,7 @@ set_package_properties(Qt6Qml PROPERTIES ) if (TARGET Qt6::Qml) -######################## include(ECMQmlModule) +########################### include(ECMQmlModule) endif() set(EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 CACHE STRING "Control the range of deprecated API excluded from the build [default=0].") diff --git a/local/recipes/kde/kf6-kitemmodels/source/src/CMakeLists.txt b/local/recipes/kde/kf6-kitemmodels/source/src/CMakeLists.txt index ffde24b35..43c09b513 100644 --- a/local/recipes/kde/kf6-kitemmodels/source/src/CMakeLists.txt +++ b/local/recipes/kde/kf6-kitemmodels/source/src/CMakeLists.txt @@ -1,6 +1,6 @@ add_subdirectory(core) if (TARGET Qt6::Qml) -####################### add_subdirectory(qml) +########################## add_subdirectory(qml) endif() ecm_qt_install_logging_categories( diff --git a/local/recipes/kde/kf6-kitemviews/source/CMakeLists.txt b/local/recipes/kde/kf6-kitemviews/source/CMakeLists.txt index cbb1b6538..6e59e0f74 100644 --- a/local/recipes/kde/kf6-kitemviews/source/CMakeLists.txt +++ b/local/recipes/kde/kf6-kitemviews/source/CMakeLists.txt @@ -63,6 +63,9 @@ find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) set(EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 CACHE STRING "Control the range of deprecated API excluded from the build [default=0].") diff --git a/local/recipes/kde/kf6-kjobwidgets/source/CMakeLists.txt b/local/recipes/kde/kf6-kjobwidgets/source/CMakeLists.txt index f9e938634..a67e16f30 100644 --- a/local/recipes/kde/kf6-kjobwidgets/source/CMakeLists.txt +++ b/local/recipes/kde/kf6-kjobwidgets/source/CMakeLists.txt @@ -65,6 +65,9 @@ find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) if(NOT WIN32 AND NOT APPLE AND NOT ANDROID AND NOT HAIKU) option(WITH_X11 "Build with support for QX11Info::appUserTime()" ON) diff --git a/local/recipes/kde/kf6-ktextwidgets/source/CMakeLists.txt b/local/recipes/kde/kf6-ktextwidgets/source/CMakeLists.txt index 31f1f0234..1bb0c4504 100644 --- a/local/recipes/kde/kf6-ktextwidgets/source/CMakeLists.txt +++ b/local/recipes/kde/kf6-ktextwidgets/source/CMakeLists.txt @@ -80,6 +80,9 @@ find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) if (WITH_TEXT_TO_SPEECH) find_package(Qt6 ${REQUIRED_QT_VERSION} CONFIG REQUIRED TextToSpeech) diff --git a/local/recipes/kde/kf6-kxmlgui/source/src/kswitchlanguagedialog_p.cpp b/local/recipes/kde/kf6-kxmlgui/source/src/kswitchlanguagedialog_p.cpp index bcf34250a..56903c481 100644 --- a/local/recipes/kde/kf6-kxmlgui/source/src/kswitchlanguagedialog_p.cpp +++ b/local/recipes/kde/kf6-kxmlgui/source/src/kswitchlanguagedialog_p.cpp @@ -74,10 +74,10 @@ void initializeLanguages() // Ideally setting the LANGUAGE would change the default QLocale too // but unfortunately this is too late since the QCoreApplication constructor // already created a QLocale at this stage so we need to set the reset it -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // by triggering the creation and destruction of a QSystemLocale +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // by triggering the creation and destruction of a QSystemLocale // this is highly dependent on Qt internals, so may break, but oh well -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// QSystemLocale *dummy = new QSystemLocale(); -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// delete dummy; +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// QSystemLocale *dummy = new QSystemLocale(); +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// delete dummy; } } diff --git a/local/recipes/kde/kf6-solid/source/CMakeLists.txt b/local/recipes/kde/kf6-solid/source/CMakeLists.txt index c2c90e10d..783445e9d 100644 --- a/local/recipes/kde/kf6-solid/source/CMakeLists.txt +++ b/local/recipes/kde/kf6-solid/source/CMakeLists.txt @@ -78,7 +78,7 @@ set_package_properties(PList PROPERTIES if (CMAKE_SYSTEM_NAME MATCHES Linux) # Used by the UDisks backend on Linux - ###############################################################find_package(LibMount) + ##################################################################find_package(LibMount) set_package_properties(LibMount PROPERTIES TYPE REQUIRED) endif() diff --git a/local/recipes/qt/qtbase/source/src/corelib/CMakeLists.txt b/local/recipes/qt/qtbase/source/src/corelib/CMakeLists.txt index 2532400dd..bb3c9b020 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/CMakeLists.txt +++ b/local/recipes/qt/qtbase/source/src/corelib/CMakeLists.txt @@ -1208,6 +1208,97 @@ qt_internal_extend_target(Core CONDITION REDOX io/qstorageinfo_unix.cpp ) +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + qt_internal_extend_target(Core CONDITION QT_FEATURE_cpp_winrt SOURCES platform/windows/qfactorycacheregistration_p.h @@ -1243,6 +1334,97 @@ qt_internal_extend_target(Core CONDITION REDOX io/qstorageinfo_unix.cpp ) +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + +# Redox: POSIX statvfs, not Linux statfs +qt_internal_extend_target(Core CONDITION REDOX + SOURCES + io/qstandardpaths_unix.cpp + io/qstorageinfo_unix.cpp +) + qt_internal_extend_target(Core CONDITION QT_FEATURE_itemmodel SOURCES itemmodels/qabstractitemmodel.cpp itemmodels/qabstractitemmodel.h itemmodels/qabstractitemmodel_p.h diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qtypes.h b/local/recipes/qt/qtbase/source/src/corelib/global/qtypes.h index 68833cb0e..7183718bb 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qtypes.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qtypes.h @@ -178,6 +178,19 @@ static_assert(std::is_signed_v, #ifndef __cplusplus #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #ifndef static_assert #define static_assert _Static_assert #endif diff --git a/local/recipes/qt/qtbase/source/src/network/socket/qnativesocketengine_unix.cpp b/local/recipes/qt/qtbase/source/src/network/socket/qnativesocketengine_unix.cpp index a79c5b157..30a86a5db 100644 --- a/local/recipes/qt/qtbase/source/src/network/socket/qnativesocketengine_unix.cpp +++ b/local/recipes/qt/qtbase/source/src/network/socket/qnativesocketengine_unix.cpp @@ -1123,6 +1123,19 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l } if (msg.msg_namelen == sizeof(aa.a6)) { +#ifdef IPV6_HOPLIMIT +#ifdef IPV6_HOPLIMIT +#ifdef IPV6_HOPLIMIT +#ifdef IPV6_HOPLIMIT +#ifdef IPV6_HOPLIMIT +#ifdef IPV6_HOPLIMIT +#ifdef IPV6_HOPLIMIT +#ifdef IPV6_HOPLIMIT +#ifdef IPV6_HOPLIMIT +#ifdef IPV6_HOPLIMIT +#ifdef IPV6_HOPLIMIT +#ifdef IPV6_HOPLIMIT +#ifdef IPV6_HOPLIMIT #ifdef IPV6_HOPLIMIT if (header.hopLimit != -1) { msg.msg_controllen += CMSG_SPACE(sizeof(int)); @@ -1132,6 +1145,19 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l memcpy(CMSG_DATA(cmsgptr), &header.hopLimit, sizeof(int)); cmsgptr = reinterpret_cast(reinterpret_cast(cmsgptr) + CMSG_SPACE(sizeof(int))); } +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif #endif if (header.ifindex != 0 || !header.senderAddress.isNull()) { struct in6_pktinfo *data = reinterpret_cast(CMSG_DATA(cmsgptr)); diff --git a/local/recipes/qt/qtbase/source/src/network/socket/qnet_unix_p.h b/local/recipes/qt/qtbase/source/src/network/socket/qnet_unix_p.h index f24189fb6..1fbf89be4 100644 --- a/local/recipes/qt/qtbase/source/src/network/socket/qnet_unix_p.h +++ b/local/recipes/qt/qtbase/source/src/network/socket/qnet_unix_p.h @@ -22,6 +22,19 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #if defined(Q_OS_VXWORKS) diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/hardwareintegration/qwaylandclientbufferintegration_p.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/hardwareintegration/qwaylandclientbufferintegration_p.h index e40ac2fa7..b79b1e8ff 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/hardwareintegration/qwaylandclientbufferintegration_p.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/hardwareintegration/qwaylandclientbufferintegration_p.h @@ -53,9 +53,35 @@ public: #if QT_CONFIG(opengl) virtual QWaylandWindow *createEglWindow(QWindow *window) = 0; +#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) #if QT_CONFIG(opengl) virtual QPlatformOpenGLContext *createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const = 0; #endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ #endif virtual bool canCreatePlatformOffscreenSurface() const { return false; } #if QT_CONFIG(opengl) @@ -70,9 +96,35 @@ public: }; virtual void *nativeResource(NativeResource /*resource*/) { return nullptr; } #if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) #if QT_CONFIG(opengl) virtual void *nativeResourceForContext(NativeResource /*resource*/, QPlatformOpenGLContext */*context*/) { return nullptr; } #endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ +#endif /* QT_CONFIG(opengl) */ #endif }; diff --git a/local/recipes/system/redbear-greeter/source/ui/CMakeLists.txt b/local/recipes/system/redbear-greeter/source/ui/CMakeLists.txt index a5f85a2b2..55edd4c88 100644 --- a/local/recipes/system/redbear-greeter/source/ui/CMakeLists.txt +++ b/local/recipes/system/redbear-greeter/source/ui/CMakeLists.txt @@ -16,6 +16,9 @@ qt_add_executable(redbear-greeter-ui ) target_compile_options(redbear-greeter-ui PRIVATE -fcf-protection=none) +if(REDOX) + target_compile_options(redbear-greeter-ui PRIVATE -include ${CMAKE_CURRENT_SOURCE_DIR}/redox_stdlib_compat.h) +endif() target_link_options(redbear-greeter-ui PRIVATE -fcf-protection=none) target_link_libraries(redbear-greeter-ui PRIVATE diff --git a/local/recipes/system/redbear-greeter/source/ui/Main.qml b/local/recipes/system/redbear-greeter/source/ui/Main.qml index 7d8f42964..075bd466f 100644 --- a/local/recipes/system/redbear-greeter/source/ui/Main.qml +++ b/local/recipes/system/redbear-greeter/source/ui/Main.qml @@ -77,15 +77,7 @@ ApplicationWindow { // Subtle vignette Rectangle { anchors.fill: parent - gradient: RadialGradient { - centerX: parent.width / 2 - centerY: parent.height / 2 - centerRadius: parent.width * 0.55 - focalX: centerX - focalY: centerY - GradientStop { position: 0.0; color: "#00000000" } - GradientStop { position: 1.0; color: "#cc000000" } - } + color: "#66000000" } } @@ -171,12 +163,7 @@ ApplicationWindow { anchors.right: parent.right height: 40 radius: parent.radius - gradient: LinearGradient { - startX: 0; startY: 0 - endX: 0; endY: 40 - GradientStop { position: 0.0; color: "#18ffffff" } - GradientStop { position: 1.0; color: "#00ffffff" } - } + color: "#10ffffff" } } diff --git a/local/recipes/system/redbear-greeter/source/ui/redox_stdlib_compat.h b/local/recipes/system/redbear-greeter/source/ui/redox_stdlib_compat.h new file mode 100644 index 000000000..c93dc38b5 --- /dev/null +++ b/local/recipes/system/redbear-greeter/source/ui/redox_stdlib_compat.h @@ -0,0 +1,5 @@ +#pragma once + +#ifdef __redox__ +typedef long double c_longdouble; +#endif diff --git a/local/recipes/system/redbear-hwutils/source/src/bin/cmdline.rs b/local/recipes/system/redbear-hwutils/source/src/bin/cmdline.rs index 15b5a6d0d..af6ddbe95 100644 --- a/local/recipes/system/redbear-hwutils/source/src/bin/cmdline.rs +++ b/local/recipes/system/redbear-hwutils/source/src/bin/cmdline.rs @@ -36,4 +36,4 @@ fn main() { } println!("{}", env_data); -} \ No newline at end of file +} diff --git a/local/recipes/system/redbear-hwutils/source/src/bin/lspci.rs b/local/recipes/system/redbear-hwutils/source/src/bin/lspci.rs index aeb710c9d..04468b3f7 100644 --- a/local/recipes/system/redbear-hwutils/source/src/bin/lspci.rs +++ b/local/recipes/system/redbear-hwutils/source/src/bin/lspci.rs @@ -211,10 +211,8 @@ fn run() -> Result<(), String> { print!(" runtime-mode: {mode}"); } if let Some(params) = resolve_driver_params(&loc_key) { - let param_str: Vec = params - .iter() - .map(|(k, v)| format!("{}={}", k, v)) - .collect(); + let param_str: Vec = + params.iter().map(|(k, v)| format!("{}={}", k, v)).collect(); print!(" driver-params: {}", param_str.join(" ")); } println!(); diff --git a/local/recipes/system/redbear-hwutils/source/src/bin/redbear-boot-check.rs b/local/recipes/system/redbear-hwutils/source/src/bin/redbear-boot-check.rs index 1baef1914..013df22fa 100644 --- a/local/recipes/system/redbear-hwutils/source/src/bin/redbear-boot-check.rs +++ b/local/recipes/system/redbear-hwutils/source/src/bin/redbear-boot-check.rs @@ -9,65 +9,146 @@ const USAGE: &str = "Usage: redbear-boot-check [--json]\n\n\ Boot process runtime check. Validates critical boot services are\n\ properly ordered, DRM device is ready, and greeter is healthy."; -#[cfg(target_os = "redox")] -use std::fs; - #[derive(Clone, Copy, Debug, Eq, PartialEq)] -enum CheckResult { Pass, Fail, Skip } +enum CheckResult { + Pass, + Fail, + #[cfg(not(target_os = "redox"))] + Skip, +} impl CheckResult { fn label(self) -> &'static str { - match self { Self::Pass => "PASS", Self::Fail => "FAIL", Self::Skip => "SKIP" } + match self { + Self::Pass => "PASS", + Self::Fail => "FAIL", + #[cfg(not(target_os = "redox"))] + Self::Skip => "SKIP", + } } } -struct Check { name: String, result: CheckResult, detail: String } +struct Check { + name: String, + result: CheckResult, + detail: String, +} impl Check { fn pass(name: &str, detail: &str) -> Self { - Check { name: name.to_string(), result: CheckResult::Pass, detail: detail.to_string() } + Check { + name: name.to_string(), + result: CheckResult::Pass, + detail: detail.to_string(), + } } fn fail(name: &str, detail: &str) -> Self { - Check { name: name.to_string(), result: CheckResult::Fail, detail: detail.to_string() } + Check { + name: name.to_string(), + result: CheckResult::Fail, + detail: detail.to_string(), + } } + #[cfg(not(target_os = "redox"))] fn skip(name: &str, detail: &str) -> Self { - Check { name: name.to_string(), result: CheckResult::Skip, detail: detail.to_string() } + Check { + name: name.to_string(), + result: CheckResult::Skip, + detail: detail.to_string(), + } } } -struct Report { checks: Vec, json_mode: bool } +struct Report { + checks: Vec, + json_mode: bool, +} impl Report { - fn new(json_mode: bool) -> Self { Report { checks: Vec::new(), json_mode } } - fn add(&mut self, check: Check) { self.checks.push(check); } - fn any_failed(&self) -> bool { self.checks.iter().any(|c| c.result == CheckResult::Fail) } + fn new(json_mode: bool) -> Self { + Report { + checks: Vec::new(), + json_mode, + } + } + fn add(&mut self, check: Check) { + self.checks.push(check); + } + fn any_failed(&self) -> bool { + self.checks.iter().any(|c| c.result == CheckResult::Fail) + } fn print(&self) { - if self.json_mode { self.print_json(); } else { self.print_human(); } + if self.json_mode { + self.print_json(); + } else { + self.print_human(); + } } fn print_human(&self) { for check in &self.checks { let icon = match check.result { - CheckResult::Pass => "[PASS]", CheckResult::Fail => "[FAIL]", CheckResult::Skip => "[SKIP]", + CheckResult::Pass => "[PASS]", + CheckResult::Fail => "[FAIL]", + #[cfg(not(target_os = "redox"))] + CheckResult::Skip => "[SKIP]", }; println!("{icon} {}: {}", check.name, check.detail); } } fn print_json(&self) { #[derive(serde::Serialize)] - struct JsonCheck { name: String, result: String, detail: String } + struct JsonCheck { + name: String, + result: String, + detail: String, + } #[derive(serde::Serialize)] struct JsonReport { - pcid_spawner: bool, drm_device: bool, compositor_socket: bool, - greeter_service: bool, checks: Vec, + pcid_spawner: bool, + drm_device: bool, + compositor_socket: bool, + greeter_service: bool, + checks: Vec, } - let pcid = self.checks.iter().find(|c| c.name == "PCID_SPAWNER").map_or(false, |c| c.result == CheckResult::Pass); - let drm = self.checks.iter().find(|c| c.name == "DRM_DEVICE").map_or(false, |c| c.result == CheckResult::Pass); - let socket = self.checks.iter().find(|c| c.name == "COMPOSITOR_SOCKET").map_or(false, |c| c.result == CheckResult::Pass); - let greeter = self.checks.iter().find(|c| c.name == "GREETER_SERVICE").map_or(false, |c| c.result == CheckResult::Pass); - let checks: Vec = self.checks.iter().map(|c| JsonCheck { - name: c.name.clone(), result: c.result.label().to_string(), detail: c.detail.clone(), - }).collect(); - if let Err(err) = serde_json::to_writer(std::io::stdout(), &JsonReport { pcid_spawner: pcid, drm_device: drm, compositor_socket: socket, greeter_service: greeter, checks }) { + let pcid = self + .checks + .iter() + .find(|c| c.name == "PCID_SPAWNER") + .map_or(false, |c| c.result == CheckResult::Pass); + let drm = self + .checks + .iter() + .find(|c| c.name == "DRM_DEVICE") + .map_or(false, |c| c.result == CheckResult::Pass); + let socket = self + .checks + .iter() + .find(|c| c.name == "COMPOSITOR_SOCKET") + .map_or(false, |c| c.result == CheckResult::Pass); + let greeter = self + .checks + .iter() + .find(|c| c.name == "GREETER_SERVICE") + .map_or(false, |c| c.result == CheckResult::Pass); + let checks: Vec = self + .checks + .iter() + .map(|c| JsonCheck { + name: c.name.clone(), + result: c.result.label().to_string(), + detail: c.detail.clone(), + }) + .collect(); + if let Err(err) = serde_json::to_writer( + std::io::stdout(), + &JsonReport { + pcid_spawner: pcid, + drm_device: drm, + compositor_socket: socket, + greeter_service: greeter, + checks, + }, + ) { eprintln!("{PROGRAM}: failed to serialize JSON: {err}"); } } @@ -79,7 +160,10 @@ fn parse_args() -> Result { for arg in std::env::args().skip(1) { match arg.as_str() { "--json" => json_mode = true, - "-h" | "--help" => { println!("{USAGE}"); return Err(String::new()); } + "-h" | "--help" => { + println!("{USAGE}"); + return Err(String::new()); + } _ => return Err(format!("unsupported argument: {arg}")), } } @@ -91,9 +175,15 @@ fn check_pcid_spawner() -> Check { let service = "/usr/lib/init.d/00_pcid-spawner.service"; if std::path::Path::new(service).exists() { if std::path::Path::new("/scheme/pci").exists() { - Check::pass("PCID_SPAWNER", "pcid-spawner service present, /scheme/pci registered") + Check::pass( + "PCID_SPAWNER", + "pcid-spawner service present, /scheme/pci registered", + ) } else { - Check::fail("PCID_SPAWNER", "pcid-spawner installed but /scheme/pci not registered") + Check::fail( + "PCID_SPAWNER", + "pcid-spawner installed but /scheme/pci not registered", + ) } } else { Check::fail("PCID_SPAWNER", "pcid-spawner service not found") @@ -105,13 +195,17 @@ fn check_drm_device() -> Check { if std::path::Path::new("/scheme/drm/card0").exists() { Check::pass("DRM_DEVICE", "/scheme/drm/card0 registered") } else { - Check::fail("DRM_DEVICE", "/scheme/drm/card0 not found — DRM backend unavailable") + Check::fail( + "DRM_DEVICE", + "/scheme/drm/card0 not found — DRM backend unavailable", + ) } } #[cfg(target_os = "redox")] fn check_compositor_socket() -> Check { - let runtime = std::env::var("XDG_RUNTIME_DIR").unwrap_or_else(|_| "/tmp/run/redbear-greeter".into()); + let runtime = + std::env::var("XDG_RUNTIME_DIR").unwrap_or_else(|_| "/tmp/run/redbear-greeter".into()); let display = std::env::var("WAYLAND_DISPLAY").unwrap_or_else(|_| "wayland-0".into()); let socket = format!("{}/{}", runtime, display); if std::path::Path::new(&socket).exists() { @@ -132,7 +226,10 @@ fn check_greeter_service() -> Check { if std::path::Path::new("/run/redbear-greeterd.sock").exists() { Check::pass("GREETER_SERVICE", "greeterd binary present, socket active") } else { - Check::pass("GREETER_SERVICE", "greeterd binary present (socket may not be ready yet)") + Check::pass( + "GREETER_SERVICE", + "greeterd binary present (socket may not be ready yet)", + ) } } else { Check::fail("GREETER_SERVICE", "greeterd binary not found") @@ -140,18 +237,29 @@ fn check_greeter_service() -> Check { } #[cfg(not(target_os = "redox"))] -fn check_pcid_spawner() -> Check { Check::skip("PCID_SPAWNER", "requires Redox runtime") } +fn check_pcid_spawner() -> Check { + Check::skip("PCID_SPAWNER", "requires Redox runtime") +} #[cfg(not(target_os = "redox"))] -fn check_drm_device() -> Check { Check::skip("DRM_DEVICE", "requires Redox runtime") } +fn check_drm_device() -> Check { + Check::skip("DRM_DEVICE", "requires Redox runtime") +} #[cfg(not(target_os = "redox"))] -fn check_compositor_socket() -> Check { Check::skip("COMPOSITOR_SOCKET", "requires Redox runtime") } +fn check_compositor_socket() -> Check { + Check::skip("COMPOSITOR_SOCKET", "requires Redox runtime") +} #[cfg(not(target_os = "redox"))] -fn check_greeter_service() -> Check { Check::skip("GREETER_SERVICE", "requires Redox runtime") } +fn check_greeter_service() -> Check { + Check::skip("GREETER_SERVICE", "requires Redox runtime") +} fn run() -> Result<(), String> { #[cfg(not(target_os = "redox"))] { - if std::env::args().any(|a| a == "-h" || a == "--help") { println!("{USAGE}"); return Err(String::new()); } + if std::env::args().any(|a| a == "-h" || a == "--help") { + println!("{USAGE}"); + return Err(String::new()); + } println!("{PROGRAM}: boot check requires Redox runtime"); return Ok(()); } @@ -164,14 +272,18 @@ fn run() -> Result<(), String> { report.add(check_compositor_socket()); report.add(check_greeter_service()); report.print(); - if report.any_failed() { return Err("one or more boot checks failed".to_string()); } + if report.any_failed() { + return Err("one or more boot checks failed".to_string()); + } Ok(()) } } fn main() { if let Err(err) = run() { - if err.is_empty() { process::exit(0); } + if err.is_empty() { + process::exit(0); + } eprintln!("{PROGRAM}: {err}"); process::exit(1); } diff --git a/local/recipes/system/redbear-hwutils/source/src/bin/redbear-greeter-check.rs b/local/recipes/system/redbear-hwutils/source/src/bin/redbear-greeter-check.rs index 01a2a54ef..a738b6d76 100644 --- a/local/recipes/system/redbear-hwutils/source/src/bin/redbear-greeter-check.rs +++ b/local/recipes/system/redbear-hwutils/source/src/bin/redbear-greeter-check.rs @@ -18,12 +18,12 @@ const AUTHD_BIN: &str = "/usr/bin/redbear-authd"; const SESSION_LAUNCH_BIN: &str = "/usr/bin/redbear-session-launch"; const GREETER_BACKGROUND: &str = "/usr/share/redbear/greeter/background.png"; const GREETER_ICON: &str = "/usr/share/redbear/greeter/icon.png"; -const AUTHD_SERVICE: &str = "/usr/lib/init.d/19_redbear-authd.service"; -const DISPLAY_SHIM_SERVICE: &str = "/usr/lib/init.d/20_display.service"; -const GREETER_SERVICE: &str = "/usr/lib/init.d/20_greeter.service"; -const ACTIVATE_CONSOLE_SERVICE: &str = "/usr/lib/init.d/29_activate_console.service"; -const CONSOLE_SERVICE: &str = "/usr/lib/init.d/30_console.service"; -const DEBUG_CONSOLE_SERVICE: &str = "/usr/lib/init.d/31_debug_console.service"; +const AUTHD_SERVICE: &str = "/etc/init.d/19_redbear-authd.service"; +const DISPLAY_SHIM_SERVICE: &str = "/etc/init.d/20_display.service"; +const GREETER_SERVICE: &str = "/etc/init.d/20_greeter.service"; +const ACTIVATE_CONSOLE_SERVICE: &str = "/etc/init.d/29_activate_console.service"; +const CONSOLE_SERVICE: &str = "/etc/init.d/30_console.service"; +const DEBUG_CONSOLE_SERVICE: &str = "/etc/init.d/31_debug_console.service"; const VALIDATION_REQUEST: &str = "/run/redbear-kde-session.validation-request"; const VALIDATION_SUCCESS: &str = "/run/redbear-kde-session.validation-success"; diff --git a/local/recipes/system/redbear-hwutils/source/src/bin/redbear-phase1-drm-check.rs b/local/recipes/system/redbear-hwutils/source/src/bin/redbear-phase1-drm-check.rs index e565ff95c..16e35b1c4 100644 --- a/local/recipes/system/redbear-hwutils/source/src/bin/redbear-phase1-drm-check.rs +++ b/local/recipes/system/redbear-hwutils/source/src/bin/redbear-phase1-drm-check.rs @@ -60,14 +60,6 @@ impl Check { detail: detail.to_string(), } } - - fn skip(name: &str, detail: &str) -> Self { - Check { - name: name.to_string(), - result: CheckResult::Skip, - detail: detail.to_string(), - } - } } #[cfg(target_os = "redox")] @@ -253,7 +245,7 @@ fn check_card_responds() -> Check { "CARD0_RESPONDS", &format!("{} byte(s) from card node", content.len()), ), - Ok(content) => Check::fail("CARD0_RESPONDS", "card node returned empty response"), + Ok(_) => Check::fail("CARD0_RESPONDS", "card node returned empty response"), Err(msg) => Check::fail("CARD0_RESPONDS", &msg), } } diff --git a/local/recipes/system/redbear-hwutils/source/src/bin/redbear-phase1-udev-check.rs b/local/recipes/system/redbear-hwutils/source/src/bin/redbear-phase1-udev-check.rs index f15cc3c05..e7a9d802b 100644 --- a/local/recipes/system/redbear-hwutils/source/src/bin/redbear-phase1-udev-check.rs +++ b/local/recipes/system/redbear-hwutils/source/src/bin/redbear-phase1-udev-check.rs @@ -190,7 +190,16 @@ fn overall_success(report: &Report, config: &Config) -> bool { (!config.keyboard || report.keyboard_count > 0), (!config.pointer || report.pointer_count > 0), (!config.drm || report.drm_count > 0), - ].iter().map(|&pass| if pass { CheckStatus::Pass("ok".to_string()) } else { CheckStatus::Fail("none found".to_string()) }).collect(); + ] + .iter() + .map(|&pass| { + if pass { + CheckStatus::Pass("ok".to_string()) + } else { + CheckStatus::Fail("none found".to_string()) + } + }) + .collect(); checks.iter().all(|c| matches!(c, CheckStatus::Pass(_))) } diff --git a/local/recipes/system/redbear-hwutils/source/src/bin/redbear-phase4-kde-check.rs b/local/recipes/system/redbear-hwutils/source/src/bin/redbear-phase4-kde-check.rs index 66983e04d..17b6cc5e4 100644 --- a/local/recipes/system/redbear-hwutils/source/src/bin/redbear-phase4-kde-check.rs +++ b/local/recipes/system/redbear-hwutils/source/src/bin/redbear-phase4-kde-check.rs @@ -234,7 +234,10 @@ fn check_kf6_libraries() -> Check { if missing.is_empty() { Check::pass( "KF6_LIBRARIES", - format!("{found}/{} key KF6 libraries found", KEY_KF6_LIBRARIES.len()), + format!( + "{found}/{} key KF6 libraries found", + KEY_KF6_LIBRARIES.len() + ), ) } else { let preview = missing @@ -245,7 +248,10 @@ fn check_kf6_libraries() -> Check { .join(", "); Check::pass( "KF6_LIBRARIES", - format!("{found}/{} found, missing: {preview}", KEY_KF6_LIBRARIES.len()), + format!( + "{found}/{} found, missing: {preview}", + KEY_KF6_LIBRARIES.len() + ), ) } } else { diff --git a/local/recipes/system/redbear-hwutils/source/src/bin/redbear-phase5-cs-check.rs b/local/recipes/system/redbear-hwutils/source/src/bin/redbear-phase5-cs-check.rs index 70d59ca2a..c70cb0f8b 100644 --- a/local/recipes/system/redbear-hwutils/source/src/bin/redbear-phase5-cs-check.rs +++ b/local/recipes/system/redbear-hwutils/source/src/bin/redbear-phase5-cs-check.rs @@ -418,15 +418,11 @@ fn run_redox(json_mode: bool) -> Result<(), String> { } }; - let mut exporter_handle = None; - let mut importer_src_handle = None; - let mut importer_dst_handle = None; - let create_exporter = DrmGemCreateWire { size: 4096, ..DrmGemCreateWire::default() }; - match drm_query( + let exporter_handle = match drm_query( &mut exporter, DRM_IOCTL_GEM_CREATE, bytes_of(&create_exporter), @@ -434,7 +430,6 @@ fn run_redox(json_mode: bool) -> Result<(), String> { .and_then(|response| decode_wire_exact::(&response)) { Ok(created) => { - exporter_handle = Some(created.handle); report.add(Check::pass( "GEM_BUFFER_ALLOCATION", &format!( @@ -442,6 +437,7 @@ fn run_redox(json_mode: bool) -> Result<(), String> { created.handle ), )); + created.handle } Err(err) => { report.add(Check::fail("GEM_BUFFER_ALLOCATION", &err)); @@ -464,81 +460,82 @@ fn run_redox(json_mode: bool) -> Result<(), String> { report.print(); return Err("one or more Phase 5 CS checks failed".to_string()); } - } + }; - if let Some(handle) = exporter_handle { - let export = DrmPrimeHandleToFdWire { handle, flags: 0 }; - let prime_result = drm_query( - &mut exporter, - DRM_IOCTL_PRIME_HANDLE_TO_FD, - bytes_of(&export), - ) - .and_then(|response| decode_wire_exact::(&response)) - .and_then(|exported| { - if exported.fd < 0 { - return Err(format!( - "PRIME export returned invalid token {} for GEM {}", - exported.fd, handle - )); - } - - let import = DrmPrimeFdToHandleWire { - fd: exported.fd, - pad: 0, - }; - drm_query( - &mut importer, - DRM_IOCTL_PRIME_FD_TO_HANDLE, - bytes_of(&import), - ) - .and_then(|response| decode_wire_exact::(&response)) - .map(|imported| (exported.fd, imported.handle)) - }); - - match prime_result { - Ok((token, imported_handle)) => { - importer_src_handle = Some(imported_handle); - report.add(Check::pass( - "PRIME_BUFFER_SHARING", - &format!( - "export token {} imported as GEM handle {} on a second DRM fd", - token, imported_handle - ), - )); - } - Err(err) => { - report.add(Check::fail("PRIME_BUFFER_SHARING", &err)); - report.add(Check::skip( - "CS_IOCTL_PROTOCOL", - "blocked: PRIME import/export failed", - )); - report.add(Check::skip( - "FENCE_SYNC_SUPPORT", - "blocked: PRIME import/export failed", - )); - report.add(Check::skip( - "HARDWARE_VALIDATION_PENDING", - "real hardware rendering validation still requires bare-metal evidence", - )); - close_gem(&mut exporter, handle); - report.print(); - return Err("one or more Phase 5 CS checks failed".to_string()); - } + let export = DrmPrimeHandleToFdWire { + handle: exporter_handle, + flags: 0, + }; + let prime_result = drm_query( + &mut exporter, + DRM_IOCTL_PRIME_HANDLE_TO_FD, + bytes_of(&export), + ) + .and_then(|response| decode_wire_exact::(&response)) + .and_then(|exported| { + if exported.fd < 0 { + return Err(format!( + "PRIME export returned invalid token {} for GEM {}", + exported.fd, exporter_handle + )); } - } + + let import = DrmPrimeFdToHandleWire { + fd: exported.fd, + pad: 0, + }; + drm_query( + &mut importer, + DRM_IOCTL_PRIME_FD_TO_HANDLE, + bytes_of(&import), + ) + .and_then(|response| decode_wire_exact::(&response)) + .map(|imported| (exported.fd, imported.handle)) + }); + + let importer_src_handle = match prime_result { + Ok((token, imported_handle)) => { + report.add(Check::pass( + "PRIME_BUFFER_SHARING", + &format!( + "export token {} imported as GEM handle {} on a second DRM fd", + token, imported_handle + ), + )); + imported_handle + } + Err(err) => { + report.add(Check::fail("PRIME_BUFFER_SHARING", &err)); + report.add(Check::skip( + "CS_IOCTL_PROTOCOL", + "blocked: PRIME import/export failed", + )); + report.add(Check::skip( + "FENCE_SYNC_SUPPORT", + "blocked: PRIME import/export failed", + )); + report.add(Check::skip( + "HARDWARE_VALIDATION_PENDING", + "real hardware rendering validation still requires bare-metal evidence", + )); + close_gem(&mut exporter, exporter_handle); + report.print(); + return Err("one or more Phase 5 CS checks failed".to_string()); + } + }; let create_importer = DrmGemCreateWire { size: 4096, ..DrmGemCreateWire::default() }; - match drm_query( + let importer_dst_handle = match drm_query( &mut importer, DRM_IOCTL_GEM_CREATE, bytes_of(&create_importer), ) .and_then(|response| decode_wire_exact::(&response)) { - Ok(created) => importer_dst_handle = Some(created.handle), + Ok(created) => created.handle, Err(err) => { report.add(Check::fail( "CS_IOCTL_PROTOCOL", @@ -552,35 +549,30 @@ fn run_redox(json_mode: bool) -> Result<(), String> { "HARDWARE_VALIDATION_PENDING", "real hardware rendering validation still requires bare-metal evidence", )); - if let Some(handle) = importer_src_handle { - close_gem(&mut importer, handle); - } - if let Some(handle) = exporter_handle { - close_gem(&mut exporter, handle); - } + close_gem(&mut importer, importer_src_handle); + close_gem(&mut exporter, exporter_handle); report.print(); return Err("one or more Phase 5 CS checks failed".to_string()); } - } + }; - let submit_result = match (importer_src_handle, importer_dst_handle) { - (Some(src_handle), Some(dst_handle)) => { - let submit = RedoxPrivateCsSubmit { - src_handle, - dst_handle, - src_offset: 0, - dst_offset: 0, - byte_count: 64, - }; - drm_query( - &mut importer, - DRM_IOCTL_REDOX_PRIVATE_CS_SUBMIT, - bytes_of(&submit), - ) - .and_then(|response| decode_wire_exact::(&response)) - .map(|result| (src_handle, dst_handle, result.seqno)) - } - _ => Err("command submission prerequisites were incomplete".to_string()), + let submit_result = { + let src_handle = importer_src_handle; + let dst_handle = importer_dst_handle; + let submit = RedoxPrivateCsSubmit { + src_handle, + dst_handle, + src_offset: 0, + dst_offset: 0, + byte_count: 64, + }; + drm_query( + &mut importer, + DRM_IOCTL_REDOX_PRIVATE_CS_SUBMIT, + bytes_of(&submit), + ) + .and_then(|response| decode_wire_exact::(&response)) + .map(|result| (src_handle, dst_handle, result.seqno)) }; match submit_result { @@ -646,15 +638,9 @@ fn run_redox(json_mode: bool) -> Result<(), String> { } } - if let Some(handle) = importer_dst_handle { - close_gem(&mut importer, handle); - } - if let Some(handle) = importer_src_handle { - close_gem(&mut importer, handle); - } - if let Some(handle) = exporter_handle { - close_gem(&mut exporter, handle); - } + close_gem(&mut importer, importer_dst_handle); + close_gem(&mut importer, importer_src_handle); + close_gem(&mut exporter, exporter_handle); report.add(Check::skip( "HARDWARE_VALIDATION_PENDING", diff --git a/local/recipes/system/redbear-hwutils/source/src/bin/redbear-phase5-gpu-check.rs b/local/recipes/system/redbear-hwutils/source/src/bin/redbear-phase5-gpu-check.rs index 3fc3c8f45..a4d84adb0 100644 --- a/local/recipes/system/redbear-hwutils/source/src/bin/redbear-phase5-gpu-check.rs +++ b/local/recipes/system/redbear-hwutils/source/src/bin/redbear-phase5-gpu-check.rs @@ -5,7 +5,9 @@ use std::process; #[cfg(target_os = "redox")] -use redbear_hwutils::{PciLocation, lookup_pci_device_name, lookup_pci_vendor_name, parse_pci_location}; +use redbear_hwutils::{ + PciLocation, lookup_pci_device_name, lookup_pci_vendor_name, parse_pci_location, +}; #[cfg(target_os = "redox")] use redox_driver_sys::pci::parse_device_info_from_config_space; @@ -334,10 +336,7 @@ fn format_gpu_pci_device(device: &GpuPciDevice) -> String { let device_name = lookup_pci_device_name(device.vendor_id, device.device_id) .unwrap_or_else(|| format!("device {:04x}", device.device_id)); - format!( - "{} {} ({})", - device.location, vendor, device_name - ) + format!("{} {} ({})", device.location, vendor, device_name) } #[cfg(target_os = "redox")] diff --git a/local/recipes/system/redbear-hwutils/source/src/bin/redbear-usb-check.rs b/local/recipes/system/redbear-hwutils/source/src/bin/redbear-usb-check.rs index dd7ca27f2..5df8298f9 100644 --- a/local/recipes/system/redbear-hwutils/source/src/bin/redbear-usb-check.rs +++ b/local/recipes/system/redbear-hwutils/source/src/bin/redbear-usb-check.rs @@ -12,69 +12,165 @@ const USAGE: &str = "Usage: redbear-usb-check [--json]\n\n\ use std::fs; #[derive(Clone, Copy, Debug, Eq, PartialEq)] -enum CheckResult { Pass, Fail, Skip } +enum CheckResult { + Pass, + Fail, + Skip, +} impl CheckResult { fn label(self) -> &'static str { - match self { Self::Pass => "PASS", Self::Fail => "FAIL", Self::Skip => "SKIP" } + match self { + Self::Pass => "PASS", + Self::Fail => "FAIL", + Self::Skip => "SKIP", + } } } -struct Check { name: String, result: CheckResult, detail: String } +struct Check { + name: String, + result: CheckResult, + detail: String, +} impl Check { fn pass(name: &str, detail: &str) -> Self { - Check { name: name.to_string(), result: CheckResult::Pass, detail: detail.to_string() } + Check { + name: name.to_string(), + result: CheckResult::Pass, + detail: detail.to_string(), + } } fn fail(name: &str, detail: &str) -> Self { - Check { name: name.to_string(), result: CheckResult::Fail, detail: detail.to_string() } + Check { + name: name.to_string(), + result: CheckResult::Fail, + detail: detail.to_string(), + } } fn skip(name: &str, detail: &str) -> Self { - Check { name: name.to_string(), result: CheckResult::Skip, detail: detail.to_string() } + Check { + name: name.to_string(), + result: CheckResult::Skip, + detail: detail.to_string(), + } } } -struct Report { checks: Vec, json_mode: bool } +struct Report { + checks: Vec, + json_mode: bool, +} impl Report { - fn new(json_mode: bool) -> Self { Report { checks: Vec::new(), json_mode } } - fn add(&mut self, check: Check) { self.checks.push(check); } - fn any_failed(&self) -> bool { self.checks.iter().any(|c| c.result == CheckResult::Fail) } + fn new(json_mode: bool) -> Self { + Report { + checks: Vec::new(), + json_mode, + } + } + fn add(&mut self, check: Check) { + self.checks.push(check); + } + fn any_failed(&self) -> bool { + self.checks.iter().any(|c| c.result == CheckResult::Fail) + } fn print(&self) { - if self.json_mode { self.print_json(); } else { self.print_human(); } + if self.json_mode { + self.print_json(); + } else { + self.print_human(); + } } fn print_human(&self) { for check in &self.checks { let icon = match check.result { - CheckResult::Pass => "[PASS]", CheckResult::Fail => "[FAIL]", CheckResult::Skip => "[SKIP]", + CheckResult::Pass => "[PASS]", + CheckResult::Fail => "[FAIL]", + CheckResult::Skip => "[SKIP]", }; println!("{icon} {}: {}", check.name, check.detail); } } fn print_json(&self) { #[derive(serde::Serialize)] - struct JsonCheck { name: String, result: String, detail: String } + struct JsonCheck { + name: String, + result: String, + detail: String, + } #[derive(serde::Serialize)] struct JsonReport { - xhci_controllers: usize, usb_devices: usize, - hid_devices: usize, storage_devices: usize, checks: Vec, + xhci_controllers: usize, + usb_devices: usize, + hid_devices: usize, + storage_devices: usize, + checks: Vec, } - let xhci = self.checks.iter().find(|c| c.name == "XHCI_CONTROLLER").map_or(0, |c| { - c.detail.split(' ').next().and_then(|s| s.parse().ok()).unwrap_or(0) - }); - let devices = self.checks.iter().find(|c| c.name == "USB_DEVICES").map_or(0, |c| { - c.detail.strip_prefix("found ").and_then(|s| s.split(' ').next()).and_then(|s| s.parse().ok()).unwrap_or(0) - }); - let hid = self.checks.iter().find(|c| c.name == "USB_HID").map_or(0, |c| { - c.detail.strip_prefix("found ").and_then(|s| s.split(' ').next()).and_then(|s| s.parse().ok()).unwrap_or(0) - }); - let storage = self.checks.iter().find(|c| c.name == "USB_STORAGE").map_or(0, |c| { - c.detail.strip_prefix("found ").and_then(|s| s.split(' ').next()).and_then(|s| s.parse().ok()).unwrap_or(0) - }); - let checks: Vec = self.checks.iter().map(|c| JsonCheck { - name: c.name.clone(), result: c.result.label().to_string(), detail: c.detail.clone(), - }).collect(); - if let Err(err) = serde_json::to_writer(std::io::stdout(), &JsonReport { xhci_controllers: xhci, usb_devices: devices, hid_devices: hid, storage_devices: storage, checks }) { + let xhci = self + .checks + .iter() + .find(|c| c.name == "XHCI_CONTROLLER") + .map_or(0, |c| { + c.detail + .split(' ') + .next() + .and_then(|s| s.parse().ok()) + .unwrap_or(0) + }); + let devices = self + .checks + .iter() + .find(|c| c.name == "USB_DEVICES") + .map_or(0, |c| { + c.detail + .strip_prefix("found ") + .and_then(|s| s.split(' ').next()) + .and_then(|s| s.parse().ok()) + .unwrap_or(0) + }); + let hid = self + .checks + .iter() + .find(|c| c.name == "USB_HID") + .map_or(0, |c| { + c.detail + .strip_prefix("found ") + .and_then(|s| s.split(' ').next()) + .and_then(|s| s.parse().ok()) + .unwrap_or(0) + }); + let storage = self + .checks + .iter() + .find(|c| c.name == "USB_STORAGE") + .map_or(0, |c| { + c.detail + .strip_prefix("found ") + .and_then(|s| s.split(' ').next()) + .and_then(|s| s.parse().ok()) + .unwrap_or(0) + }); + let checks: Vec = self + .checks + .iter() + .map(|c| JsonCheck { + name: c.name.clone(), + result: c.result.label().to_string(), + detail: c.detail.clone(), + }) + .collect(); + if let Err(err) = serde_json::to_writer( + std::io::stdout(), + &JsonReport { + xhci_controllers: xhci, + usb_devices: devices, + hid_devices: hid, + storage_devices: storage, + checks, + }, + ) { eprintln!("{PROGRAM}: failed to serialize JSON: {err}"); } } @@ -86,7 +182,10 @@ fn parse_args() -> Result { for arg in std::env::args().skip(1) { match arg.as_str() { "--json" => json_mode = true, - "-h" | "--help" => { println!("{USAGE}"); return Err(String::new()); } + "-h" | "--help" => { + println!("{USAGE}"); + return Err(String::new()); + } _ => return Err(format!("unsupported argument: {arg}")), } } @@ -96,7 +195,10 @@ fn parse_args() -> Result { #[cfg(target_os = "redox")] fn list_dir(path: &str) -> Vec { match fs::read_dir(path) { - Ok(entries) => entries.filter_map(|e| e.ok()).filter_map(|e| e.file_name().to_str().map(|s| s.to_string())).collect(), + Ok(entries) => entries + .filter_map(|e| e.ok()) + .filter_map(|e| e.file_name().to_str().map(|s| s.to_string())) + .collect(), Err(_) => Vec::new(), } } @@ -105,9 +207,15 @@ fn list_dir(path: &str) -> Vec { fn check_xhci_controller() -> Check { let xhci = list_dir("/scheme/xhci"); if !xhci.is_empty() { - Check::pass("XHCI_CONTROLLER", &format!("{} xHCI controller(s): {}", xhci.len(), xhci.join(", "))) + Check::pass( + "XHCI_CONTROLLER", + &format!("{} xHCI controller(s): {}", xhci.len(), xhci.join(", ")), + ) } else { - Check::fail("XHCI_CONTROLLER", "no xHCI controllers found under /scheme/xhci") + Check::fail( + "XHCI_CONTROLLER", + "no xHCI controllers found under /scheme/xhci", + ) } } @@ -124,7 +232,10 @@ fn check_usb_devices() -> Check { total += ports.len(); } if total > 0 { - Check::pass("USB_DEVICES", &format!("found {} device(s) across {} hub(s)", total, entries.len())) + Check::pass( + "USB_DEVICES", + &format!("found {} device(s) across {} hub(s)", total, entries.len()), + ) } else { Check::skip("USB_DEVICES", "USB hubs present but no devices attached") } @@ -141,7 +252,9 @@ fn check_usb_hid() -> Check { if let Ok(data) = fs::read_to_string(&desc_path) { if let Ok(desc) = serde_json::from_str::(&data) { let class = desc.get("class").and_then(|v| v.as_u64()).unwrap_or(0); - if class == 3 { hid_count += 1; } + if class == 3 { + hid_count += 1; + } } } } @@ -149,7 +262,10 @@ fn check_usb_hid() -> Check { if hid_count > 0 { Check::pass("USB_HID", &format!("found {} HID device(s)", hid_count)) } else { - Check::skip("USB_HID", "no USB HID devices found (may need physical hardware)") + Check::skip( + "USB_HID", + "no USB HID devices found (may need physical hardware)", + ) } } @@ -164,22 +280,33 @@ fn check_usb_storage() -> Check { if let Ok(data) = fs::read_to_string(&desc_path) { if let Ok(desc) = serde_json::from_str::(&data) { let class = desc.get("class").and_then(|v| v.as_u64()).unwrap_or(0); - if class == 8 { storage_count += 1; } + if class == 8 { + storage_count += 1; + } } } } } if storage_count > 0 { - Check::pass("USB_STORAGE", &format!("found {} storage device(s)", storage_count)) + Check::pass( + "USB_STORAGE", + &format!("found {} storage device(s)", storage_count), + ) } else { - Check::skip("USB_STORAGE", "no USB storage devices found (may need physical hardware)") + Check::skip( + "USB_STORAGE", + "no USB storage devices found (may need physical hardware)", + ) } } fn run() -> Result<(), String> { #[cfg(not(target_os = "redox"))] { - if std::env::args().any(|a| a == "-h" || a == "--help") { println!("{USAGE}"); return Err(String::new()); } + if std::env::args().any(|a| a == "-h" || a == "--help") { + println!("{USAGE}"); + return Err(String::new()); + } println!("{PROGRAM}: USB check requires Redox runtime"); return Ok(()); } @@ -192,14 +319,18 @@ fn run() -> Result<(), String> { report.add(check_usb_hid()); report.add(check_usb_storage()); report.print(); - if report.any_failed() { return Err("one or more USB checks failed".to_string()); } + if report.any_failed() { + return Err("one or more USB checks failed".to_string()); + } Ok(()) } } fn main() { if let Err(err) = run() { - if err.is_empty() { process::exit(0); } + if err.is_empty() { + process::exit(0); + } eprintln!("{PROGRAM}: {err}"); process::exit(1); } diff --git a/local/recipes/system/redbear-hwutils/source/src/bin/redbear-usb-storage-check.rs b/local/recipes/system/redbear-hwutils/source/src/bin/redbear-usb-storage-check.rs index 9584cbf3b..714e820c6 100644 --- a/local/recipes/system/redbear-hwutils/source/src/bin/redbear-usb-storage-check.rs +++ b/local/recipes/system/redbear-hwutils/source/src/bin/redbear-usb-storage-check.rs @@ -16,48 +16,94 @@ const SECTOR_SIZE: usize = 512; const TEST_PATTERN: &[u8; 24] = b"REDBEAR-USB-RW-PROOF\0\0\0\0"; #[derive(Clone, Copy, Debug, Eq, PartialEq)] -enum CheckResult { Pass, Fail, Skip } +enum CheckResult { + Pass, + Fail, + Skip, +} impl CheckResult { fn label(self) -> &'static str { - match self { Self::Pass => "PASS", Self::Fail => "FAIL", Self::Skip => "SKIP" } + match self { + Self::Pass => "PASS", + Self::Fail => "FAIL", + Self::Skip => "SKIP", + } } } -struct Check { name: String, result: CheckResult, detail: String } +struct Check { + name: String, + result: CheckResult, + detail: String, +} impl Check { fn pass(name: &str, detail: &str) -> Self { - Check { name: name.to_string(), result: CheckResult::Pass, detail: detail.to_string() } + Check { + name: name.to_string(), + result: CheckResult::Pass, + detail: detail.to_string(), + } } fn fail(name: &str, detail: &str) -> Self { - Check { name: name.to_string(), result: CheckResult::Fail, detail: detail.to_string() } + Check { + name: name.to_string(), + result: CheckResult::Fail, + detail: detail.to_string(), + } } fn skip(name: &str, detail: &str) -> Self { - Check { name: name.to_string(), result: CheckResult::Skip, detail: detail.to_string() } + Check { + name: name.to_string(), + result: CheckResult::Skip, + detail: detail.to_string(), + } } } -struct Report { checks: Vec, json_mode: bool } +struct Report { + checks: Vec, + json_mode: bool, +} impl Report { - fn new(json_mode: bool) -> Self { Report { checks: Vec::new(), json_mode } } - fn add(&mut self, check: Check) { self.checks.push(check); } - fn any_failed(&self) -> bool { self.checks.iter().any(|c| c.result == CheckResult::Fail) } + fn new(json_mode: bool) -> Self { + Report { + checks: Vec::new(), + json_mode, + } + } + fn add(&mut self, check: Check) { + self.checks.push(check); + } + fn any_failed(&self) -> bool { + self.checks.iter().any(|c| c.result == CheckResult::Fail) + } fn print(&self) { - if self.json_mode { self.print_json(); } else { self.print_human(); } + if self.json_mode { + self.print_json(); + } else { + self.print_human(); + } } fn print_human(&self) { for check in &self.checks { let icon = match check.result { - CheckResult::Pass => "[PASS]", CheckResult::Fail => "[FAIL]", CheckResult::Skip => "[SKIP]", + CheckResult::Pass => "[PASS]", + CheckResult::Fail => "[FAIL]", + CheckResult::Skip => "[SKIP]", }; println!("{icon} {}: {}", check.name, check.detail); } } fn print_json(&self) { #[derive(serde::Serialize)] - struct JsonCheck { name: String, result: String, detail: String } + struct JsonCheck { + name: String, + result: String, + detail: String, + } #[derive(serde::Serialize)] struct JsonReport { device_path: String, @@ -66,21 +112,42 @@ impl Report { sector_restored: bool, checks: Vec, } - let dev = self.checks.iter().find(|c| c.name == "STORAGE_DISCOVERY") + let dev = self + .checks + .iter() + .find(|c| c.name == "STORAGE_DISCOVERY") .map_or("none".to_string(), |c| c.detail.clone()); - let written = self.checks.iter().any(|c| c.name == "STORAGE_WRITE" && c.result == CheckResult::Pass); - let verified = self.checks.iter().any(|c| c.name == "STORAGE_READBACK" && c.result == CheckResult::Pass); - let restored = self.checks.iter().any(|c| c.name == "STORAGE_RESTORE" && c.result == CheckResult::Pass); - let checks: Vec = self.checks.iter().map(|c| JsonCheck { - name: c.name.clone(), result: c.result.label().to_string(), detail: c.detail.clone(), - }).collect(); - if let Err(err) = serde_json::to_writer(std::io::stdout(), &JsonReport { - device_path: dev, - sector_written: written, - sector_verified: verified, - sector_restored: restored, - checks, - }) { + let written = self + .checks + .iter() + .any(|c| c.name == "STORAGE_WRITE" && c.result == CheckResult::Pass); + let verified = self + .checks + .iter() + .any(|c| c.name == "STORAGE_READBACK" && c.result == CheckResult::Pass); + let restored = self + .checks + .iter() + .any(|c| c.name == "STORAGE_RESTORE" && c.result == CheckResult::Pass); + let checks: Vec = self + .checks + .iter() + .map(|c| JsonCheck { + name: c.name.clone(), + result: c.result.label().to_string(), + detail: c.detail.clone(), + }) + .collect(); + if let Err(err) = serde_json::to_writer( + std::io::stdout(), + &JsonReport { + device_path: dev, + sector_written: written, + sector_verified: verified, + sector_restored: restored, + checks, + }, + ) { eprintln!("{PROGRAM}: failed to serialize JSON: {err}"); } } @@ -92,7 +159,10 @@ fn parse_args() -> Result { for arg in std::env::args().skip(1) { match arg.as_str() { "--json" => json_mode = true, - "-h" | "--help" => { println!("{USAGE}"); return Err(String::new()); } + "-h" | "--help" => { + println!("{USAGE}"); + return Err(String::new()); + } _ => return Err(format!("unsupported argument: {arg}")), } } @@ -102,8 +172,10 @@ fn parse_args() -> Result { #[cfg(target_os = "redox")] fn list_dir(path: &str) -> Vec { match fs::read_dir(path) { - Ok(entries) => entries.filter_map(|e| e.ok()) - .filter_map(|e| e.file_name().to_str().map(|s| s.to_string())).collect(), + Ok(entries) => entries + .filter_map(|e| e.ok()) + .filter_map(|e| e.file_name().to_str().map(|s| s.to_string())) + .collect(), Err(_) => Vec::new(), } } @@ -158,14 +230,25 @@ fn check_storage_discovery() -> Check { if let Ok(data) = fs::read_to_string(&desc_path) { if let Ok(desc) = serde_json::from_str::(&data) { let class = desc.get("class").and_then(|v| v.as_u64()).unwrap_or(0); - if class == 8 { storage_count += 1; } + if class == 8 { + storage_count += 1; + } } } } } - Check::pass("STORAGE_DISCOVERY", &format!("{} ({} USB storage class device(s) visible)", path, storage_count)) + Check::pass( + "STORAGE_DISCOVERY", + &format!( + "{} ({} USB storage class device(s) visible)", + path, storage_count + ), + ) } - None => Check::fail("STORAGE_DISCOVERY", "no writable block device found under /scheme/disk/"), + None => Check::fail( + "STORAGE_DISCOVERY", + "no writable block device found under /scheme/disk/", + ), } } @@ -175,17 +258,32 @@ fn check_storage_write(disk_path: &str, original_out: &mut [u8; SECTOR_SIZE]) -> use std::io::{Read, Seek, SeekFrom, Write}; let offset = TEST_SECTOR * SECTOR_SIZE as u64; - let mut f = match fs::OpenOptions::new().read(true).write(true).open(disk_path) { + let mut f = match fs::OpenOptions::new() + .read(true) + .write(true) + .open(disk_path) + { Ok(f) => f, - Err(e) => return Check::fail("STORAGE_WRITE", &format!("failed to open {} for read/write: {e}", disk_path)), + Err(e) => { + return Check::fail( + "STORAGE_WRITE", + &format!("failed to open {} for read/write: {e}", disk_path), + ); + } }; // Save original content for later restore if let Err(e) = f.seek(SeekFrom::Start(offset)) { - return Check::fail("STORAGE_WRITE", &format!("failed to seek to sector {TEST_SECTOR}: {e}")); + return Check::fail( + "STORAGE_WRITE", + &format!("failed to seek to sector {TEST_SECTOR}: {e}"), + ); } if let Err(e) = f.read_exact(original_out) { - return Check::fail("STORAGE_WRITE", &format!("failed to read original sector {TEST_SECTOR}: {e}")); + return Check::fail( + "STORAGE_WRITE", + &format!("failed to read original sector {TEST_SECTOR}: {e}"), + ); } let pattern = make_test_pattern(); @@ -193,12 +291,21 @@ fn check_storage_write(disk_path: &str, original_out: &mut [u8; SECTOR_SIZE]) -> return Check::fail("STORAGE_WRITE", &format!("failed to seek for write: {e}")); } if let Err(e) = f.write_all(&pattern) { - return Check::fail("STORAGE_WRITE", &format!("failed to write test pattern to sector {TEST_SECTOR}: {e}")); + return Check::fail( + "STORAGE_WRITE", + &format!("failed to write test pattern to sector {TEST_SECTOR}: {e}"), + ); } if let Err(e) = f.flush() { return Check::fail("STORAGE_WRITE", &format!("failed to flush write: {e}")); } - Check::pass("STORAGE_WRITE", &format!("wrote test pattern to sector {TEST_SECTOR} of {}", disk_path)) + Check::pass( + "STORAGE_WRITE", + &format!( + "wrote test pattern to sector {TEST_SECTOR} of {}", + disk_path + ), + ) } /// Read back the test sector and verify the pattern matches. @@ -209,29 +316,47 @@ fn check_storage_readback(disk_path: &str) -> Check { let mut f = match fs::File::open(disk_path) { Ok(f) => f, - Err(e) => return Check::fail("STORAGE_READBACK", &format!("failed to reopen {}: {e}", disk_path)), + Err(e) => { + return Check::fail( + "STORAGE_READBACK", + &format!("failed to reopen {}: {e}", disk_path), + ); + } }; if let Err(e) = f.seek(SeekFrom::Start(offset)) { - return Check::fail("STORAGE_READBACK", &format!("failed to seek to sector {TEST_SECTOR}: {e}")); + return Check::fail( + "STORAGE_READBACK", + &format!("failed to seek to sector {TEST_SECTOR}: {e}"), + ); } let mut buf = [0u8; SECTOR_SIZE]; if let Err(e) = f.read_exact(&mut buf) { - return Check::fail("STORAGE_READBACK", &format!("failed to read sector {TEST_SECTOR}: {e}")); + return Check::fail( + "STORAGE_READBACK", + &format!("failed to read sector {TEST_SECTOR}: {e}"), + ); } let pattern = make_test_pattern(); if buf == pattern { - Check::pass("STORAGE_READBACK", &format!("sector {TEST_SECTOR} readback matches test pattern")) + Check::pass( + "STORAGE_READBACK", + &format!("sector {TEST_SECTOR} readback matches test pattern"), + ) } else { - let first_mismatch = buf.iter().zip(pattern.iter()).enumerate() + let first_mismatch = buf + .iter() + .zip(pattern.iter()) + .enumerate() .find(|(_, (a, b))| a != b) .map(|(i, _)| i) .unwrap_or(SECTOR_SIZE); - Check::fail("STORAGE_READBACK", &format!( - "sector {TEST_SECTOR} readback mismatch at byte offset {first_mismatch}" - )) + Check::fail( + "STORAGE_READBACK", + &format!("sector {TEST_SECTOR} readback mismatch at byte offset {first_mismatch}"), + ) } } @@ -243,25 +368,42 @@ fn check_storage_restore(disk_path: &str, original: &[u8; SECTOR_SIZE]) -> Check let mut f = match fs::OpenOptions::new().write(true).open(disk_path) { Ok(f) => f, - Err(e) => return Check::fail("STORAGE_RESTORE", &format!("failed to open {} for restore: {e}", disk_path)), + Err(e) => { + return Check::fail( + "STORAGE_RESTORE", + &format!("failed to open {} for restore: {e}", disk_path), + ); + } }; if let Err(e) = f.seek(SeekFrom::Start(offset)) { - return Check::fail("STORAGE_RESTORE", &format!("failed to seek for restore: {e}")); + return Check::fail( + "STORAGE_RESTORE", + &format!("failed to seek for restore: {e}"), + ); } if let Err(e) = f.write_all(original) { - return Check::fail("STORAGE_RESTORE", &format!("failed to restore original sector: {e}")); + return Check::fail( + "STORAGE_RESTORE", + &format!("failed to restore original sector: {e}"), + ); } if let Err(e) = f.flush() { return Check::fail("STORAGE_RESTORE", &format!("failed to flush restore: {e}")); } - Check::pass("STORAGE_RESTORE", &format!("restored original content of sector {TEST_SECTOR}")) + Check::pass( + "STORAGE_RESTORE", + &format!("restored original content of sector {TEST_SECTOR}"), + ) } fn run() -> Result<(), String> { #[cfg(not(target_os = "redox"))] { - if std::env::args().any(|a| a == "-h" || a == "--help") { println!("{USAGE}"); return Err(String::new()); } + if std::env::args().any(|a| a == "-h" || a == "--help") { + println!("{USAGE}"); + return Err(String::new()); + } println!("{PROGRAM}: USB storage check requires Redox runtime"); return Ok(()); } @@ -271,7 +413,11 @@ fn run() -> Result<(), String> { let mut report = Report::new(json_mode); let discovery = check_storage_discovery(); - let disk_path = discovery.detail.split_whitespace().next().map(|s| s.to_string()); + let disk_path = discovery + .detail + .split_whitespace() + .next() + .map(|s| s.to_string()); report.add(discovery); let disk_path = match disk_path { @@ -290,24 +436,34 @@ fn run() -> Result<(), String> { if write_ok { report.add(check_storage_readback(&disk_path)); } else { - report.add(Check::skip("STORAGE_READBACK", "skipped because write check failed")); + report.add(Check::skip( + "STORAGE_READBACK", + "skipped because write check failed", + )); } if write_ok { report.add(check_storage_restore(&disk_path, &original)); } else { - report.add(Check::skip("STORAGE_RESTORE", "skipped because write check failed")); + report.add(Check::skip( + "STORAGE_RESTORE", + "skipped because write check failed", + )); } report.print(); - if report.any_failed() { return Err("one or more USB storage checks failed".to_string()); } + if report.any_failed() { + return Err("one or more USB storage checks failed".to_string()); + } Ok(()) } } fn main() { if let Err(err) = run() { - if err.is_empty() { process::exit(0); } + if err.is_empty() { + process::exit(0); + } eprintln!("{PROGRAM}: {err}"); process::exit(1); } diff --git a/local/recipes/system/redbear-wayland-guard/source/wayland_guard.c b/local/recipes/system/redbear-wayland-guard/source/wayland_guard.c new file mode 100644 index 000000000..691a6b1ee --- /dev/null +++ b/local/recipes/system/redbear-wayland-guard/source/wayland_guard.c @@ -0,0 +1,46 @@ +/* Runtime null guard for wl_proxy_add_listener — interposed via LD_PRELOAD. + * Qt6 Wayland QPA passes NULL proxies during initialization on Redox. + * This shim prevents the page fault at null+8 (proxy->object.implementation) + * by returning an error code instead of crashing. + * + * Cross-referenced with libwayland wayland-client.c:649. + */ +#define _GNU_SOURCE +#include +#include +#include + +/* Original function pointer */ +static int (*real_wl_proxy_add_listener)(void *proxy, + void (**implementation)(void), void *data) = NULL; + +static void *(*real_wl_proxy_get_display)(void *proxy) = NULL; +static unsigned int (*real_wl_proxy_get_version)(void *proxy) = NULL; + +static void init(void) { + real_wl_proxy_add_listener = dlsym(RTLD_NEXT, "wl_proxy_add_listener"); + real_wl_proxy_get_display = dlsym(RTLD_NEXT, "wl_proxy_get_display"); + real_wl_proxy_get_version = dlsym(RTLD_NEXT, "wl_proxy_get_version"); +} + +int wl_proxy_add_listener(void *proxy, + void (**implementation)(void), void *data) { + if (!real_wl_proxy_add_listener) init(); + if (!proxy) { + fprintf(stderr, "wayland-guard: wl_proxy_add_listener(NULL) prevented crash\n"); + return -1; + } + return real_wl_proxy_add_listener(proxy, implementation, data); +} + +void *wl_proxy_get_display(void *proxy) { + if (!real_wl_proxy_get_display) init(); + if (!proxy) return NULL; + return real_wl_proxy_get_display(proxy); +} + +unsigned int wl_proxy_get_version(void *proxy) { + if (!real_wl_proxy_get_version) init(); + if (!proxy) return 0; + return real_wl_proxy_get_version(proxy); +} diff --git a/local/recipes/wayland/libwayland/recipe.toml b/local/recipes/wayland/libwayland/recipe.toml index 9983eaf73..9213fdef1 100644 --- a/local/recipes/wayland/libwayland/recipe.toml +++ b/local/recipes/wayland/libwayland/recipe.toml @@ -1,9 +1,8 @@ -#TODO: Requires a narrow Redox delta for native scanner discovery during -# cross-builds and a userspace eventfd fallback because relibc lacks sys/eventfd.h. -# redox.patch keeps only the active scanner/eventfd compatibility surface. +#TODO: Requires Redox compatibility patching for missing Linux header paths and +# some POSIX/Linux-only flags during cross-builds. +# redox.patch restores the Redox compatibility stubs plus Meson scanner detection. [source] tar = "https://gitlab.freedesktop.org/wayland/wayland/-/releases/1.24.0/downloads/wayland-1.24.0.tar.xz" -blake3 = "8c3b2bc792e5e262e9fb821fb8222b376de6fdf5d7af9b86d46e51ecf79704b9" patches = ["redox.patch"] [build] @@ -15,30 +14,8 @@ dependencies = [ "libxml2", ] script = """ -COOKBOOK_CONFIGURE_FLAGS=( - --host="${GNU_TARGET}" - --prefix="/usr" - --disable-shared - --enable-static -) -COOKBOOK_MESON_FLAGS=( - --buildtype release - --wrap-mode nofallback - -Ddefault_library=static - -Dprefix=/usr -) -cookbook_meson \ - -Ddocumentation=false \ - -Dtests=false \ - -Ddtd_validation=false \ - -Dscanner=false \ - -Dc_args="['-I${COOKBOOK_SYSROOT}/include','-Wno-error']" - -for pc in "${COOKBOOK_STAGE}/usr/lib/pkgconfig/wayland-client.pc" "${COOKBOOK_STAGE}/usr/lib/pkgconfig/wayland-server.pc"; do - if [ -f "$pc" ]; then - sed -i 's/^Libs: /Libs: -lffi /' "$pc" - fi -done +DYNAMIC_INIT +cookbook_meson -Ddocumentation=false -Dtests=false -Ddtd_validation=false -Dc_args=-Wno-error """ [package] diff --git a/local/recipes/wayland/libwayland/source/src/wayland-client.c b/local/recipes/wayland/libwayland/source/src/wayland-client.c index 2464e7b75..d65206f64 100644 --- a/local/recipes/wayland/libwayland/source/src/wayland-client.c +++ b/local/recipes/wayland/libwayland/source/src/wayland-client.c @@ -649,6 +649,12 @@ WL_EXPORT int wl_proxy_add_listener(struct wl_proxy *proxy, void (**implementation)(void), void *data) { + if (!proxy) { + fprintf(stderr, "FATAL: wl_proxy_add_listener(NULL) caller=%p -- returning error +", + __builtin_return_address(0)); + return -1; + } if (proxy->flags & WL_PROXY_FLAG_WRAPPER) wl_abort("Proxy %p is a wrapper\n", proxy); @@ -2442,6 +2448,7 @@ wl_proxy_get_user_data(struct wl_proxy *proxy) WL_EXPORT uint32_t wl_proxy_get_version(struct wl_proxy *proxy) { + if (!proxy) return 0; return proxy->version; } @@ -2560,6 +2567,7 @@ wl_proxy_get_interface(struct wl_proxy *proxy) WL_EXPORT struct wl_display * wl_proxy_get_display(struct wl_proxy *proxy) { + if (!proxy) return NULL; return proxy->display; }