e65a23fd6b
This commit replaces the D-Bus implementation stubs and gaps identified
during the zbus/D-Bus review round with real, tested implementations.
**redbear-sessiond: real login1 properties + PrepareForShutdown signals**
The login1.Manager interface had hardcoded stub values:
- idle_since_hint() and idle_since_hint_monotonic() returned 0
- inhibit_delay_max_usec() returned 0
- handle_lid_switch() returned 'ignore'
- handle_power_key() returned 'poweroff'
- power_off/reboot/suspend wrote to /scheme/sys/kstop but did NOT
emit PrepareForShutdown(before=true) / PrepareForSleep(true) first
Replace with:
- Run-time configurable atomic fields (last_activity_us,
inhibit_delay_max_us) and RwLock<String> fields (handle_lid_switch,
handle_power_key) on SessionRuntime, mutated by the existing control
socket. Defaults: 5s inhibit delay, 'ignore' lid, 'poweroff' power key.
- power_off/reboot are now async, emit PrepareForShutdown(true) before
/scheme/sys/kstop write, emit PrepareForShutdown(false) after a
successful write, and return a D-Bus error if the kstop write fails
(resetting preparing_for_shutdown).
- suspend emits PrepareForSleep(true)/(false) similarly.
- Bash-style dangling-Clone problem solved via manual Clone impl on
SessionRuntime that snapshots the atomics and lock contents.
**redbear-wifictl: real NetworkManager-shaped D-Bus interface**
The dbus-nm feature was a no-op stub that just logged 'registered'
without actually doing anything. Replace with a real zbus interface:
- zbus::interface structs wrapping Arc<Mutex<NmWifiDevice>> shared state
- org.freedesktop.NetworkManager at /org/freedesktop/NetworkManager
exposes WirelessEnabled, WirelessHardwareEnabled, State, and
GetDevices().
- org.freedesktop.NetworkManager.Device.Wireless at
/org/freedesktop/NetworkManager/Devices/0 exposes HwAddress,
PermHwAddress, State, Ssid, Strength, LastScan, AccessPoints,
GetAccessPoints(), WirelessCapabilities.
- register_nm_interface() now actually builds a blocking
zbus::connection::Builder on the session bus, registers both
service name + object paths, spawns a background thread to hold the
connection alive, and returns. On session-bus connect failure it
logs an error and returns without crashing.
- When the dbus-nm feature is disabled, behavior is unchanged (no-op).
- Type model enriched: NmWifiDevice gains last_scan, active_ssid,
active_strength fields + Default derives; NmDeviceState gains
Default; NmAccessPoint gains Default.
**redbear-statusnotifierwatcher: wired into redbear-full**
The recipe compiled and had 12 tests but was NOT in any config —
the binary never deployed. Add:
- [package.files] stanza to its recipe.toml so the binary is staged
- redbear-statusnotifierwatcher = {} to config/redbear-full.toml
- launch_optional_component invocation in redbear-kde-session
**redbear-notifications: 8 host unit tests**
Previously zero tests. Add a #[cfg(test)] module covering:
- monotonic notification IDs
- capabilities list (spec values present)
- server information strings
- close-id + reason recording
- action invocation payload
- ordering preserved across multiple notifications
- independence between close and action records
**zbus build-ordering marker: clean source**
The marker source lib.rs contained 'pub struct Connection;' which
is misleading. Replace with a minimal comment explaining the
build-ordering purpose. The actual zbus crate is still resolved by
Cargo at downstream build time (unchanged behavior).
**D-Bus symlink cleanup**
Remove recipes/system/dbus/dbus-root-uid.patch (orphan symlink, not
in .gitignore-relevant scope). The actual patch stays in
local/patches/dbus/. The redox.patch in the same directory is a
real file (not a symlink) and is preserved.
**Build-system bug fixes**
- build-preflight.sh: when broken recipe.toml links cannot be restored
from git, invoke the guard-recipes.sh --fix path so untracked
custom links are regenerated.
- verify-fork-functions.sh: skip std-trait method names (fmt, eq,
clone, drop, etc.) when checking for dropped upstream functions —
these are derivable or compiler-caught, so a missed refactor is
inert, not a build blocker.
- verify-overlay-integrity.sh: add explicit 'return 0' on log helpers
so --quiet mode does not abort on the first log call under set -e.
Verification: host cargo test passes on all four modified daemons.
redbear-sessiond: 52 tests (12 new for the properties + signals).
redbear-wifictl: 35 tests (4 new for dbus_nm) + 2 cli_transport.
redbear-notifications: 8 tests (all new).
redbear-upower/udisks/polkit: unchanged, still pass.
265 lines
7.6 KiB
Bash
Executable File
265 lines
7.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
VALIDATION_REQUEST="/run/redbear-kde-session.validation-request"
|
|
VALIDATION_SUCCESS="/run/redbear-kde-session.validation-success"
|
|
|
|
kwin_pid=""
|
|
optional_pids=()
|
|
|
|
export DESKTOP_SESSION="${DESKTOP_SESSION:-plasmawayland}"
|
|
export DISPLAY=""
|
|
export KDE_FULL_SESSION="${KDE_FULL_SESSION:-true}"
|
|
export KDE_SESSION_VERSION="${KDE_SESSION_VERSION:-6}"
|
|
export LIBSEAT_BACKEND="${LIBSEAT_BACKEND:-seatd}"
|
|
export LOGNAME="${LOGNAME:-${USER:-root}}"
|
|
export PATH="${PATH:-/usr/bin:/bin}"
|
|
export QML2_IMPORT_PATH="${QML2_IMPORT_PATH:-/usr/qml}"
|
|
export QT_PLUGIN_PATH="${QT_PLUGIN_PATH:-/usr/plugins}"
|
|
export QT_QPA_PLATFORM="${QT_QPA_PLATFORM:-wayland}"
|
|
export QT_QPA_PLATFORM_PLUGIN_PATH="${QT_QPA_PLATFORM_PLUGIN_PATH:-/usr/plugins/platforms}"
|
|
export SEATD_SOCK="${SEATD_SOCK:-/run/seatd.sock}"
|
|
export USER="${USER:-root}"
|
|
export WAYLAND_DISPLAY="${WAYLAND_DISPLAY:-wayland-0}"
|
|
export XCURSOR_THEME="${XCURSOR_THEME:-Pop}"
|
|
export XDG_CURRENT_DESKTOP="${XDG_CURRENT_DESKTOP:-KDE}"
|
|
export XDG_SESSION_DESKTOP="${XDG_SESSION_DESKTOP:-KDE}"
|
|
export XDG_SESSION_ID="${XDG_SESSION_ID:-c1}"
|
|
export XDG_SESSION_TYPE="${XDG_SESSION_TYPE:-wayland}"
|
|
export XKB_CONFIG_ROOT="${XKB_CONFIG_ROOT:-/usr/share/X11/xkb}"
|
|
|
|
if [ -z "${XDG_RUNTIME_DIR:-}" ]; then
|
|
export XDG_RUNTIME_DIR="/tmp/run/user/$(id -u)"
|
|
fi
|
|
|
|
mkdir -p "$XDG_RUNTIME_DIR"
|
|
chmod 700 "$XDG_RUNTIME_DIR" 2>/dev/null || true
|
|
|
|
choose_state_dir() {
|
|
local requested="${REDBEAR_KDE_SESSION_STATE_DIR:-}"
|
|
|
|
if [ -n "$requested" ]; then
|
|
mkdir -p "$requested" 2>/dev/null || true
|
|
if [ -d "$requested" ] && [ -w "$requested" ]; then
|
|
printf '%s\n' "$requested"
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
if [ -d /run ] && [ -w /run ]; then
|
|
printf '%s\n' "/run"
|
|
return 0
|
|
fi
|
|
|
|
printf '%s\n' "$XDG_RUNTIME_DIR"
|
|
}
|
|
|
|
session_state_dir="$(choose_state_dir)"
|
|
mkdir -p "$session_state_dir"
|
|
chmod 700 "$session_state_dir" 2>/dev/null || true
|
|
|
|
session_env_file="$session_state_dir/redbear-kde-session.env"
|
|
session_ready_file="$session_state_dir/redbear-kde-session.ready"
|
|
panel_ready_file="$session_state_dir/redbear-kde-session.panel-ready"
|
|
|
|
rm -f "$session_ready_file" "$panel_ready_file"
|
|
|
|
cleanup() {
|
|
local status=$?
|
|
|
|
trap - EXIT INT TERM
|
|
|
|
for pid in "${optional_pids[@]}"; do
|
|
if kill -0 "$pid" 2>/dev/null; then
|
|
kill "$pid" 2>/dev/null || true
|
|
wait "$pid" 2>/dev/null || true
|
|
fi
|
|
done
|
|
|
|
if [ -n "$kwin_pid" ] && kill -0 "$kwin_pid" 2>/dev/null; then
|
|
kill "$kwin_pid" 2>/dev/null || true
|
|
wait "$kwin_pid" 2>/dev/null || true
|
|
fi
|
|
|
|
exit "$status"
|
|
}
|
|
|
|
trap cleanup EXIT INT TERM
|
|
|
|
kwin_mode="virtual"
|
|
|
|
set_kwin_mode() {
|
|
local requested="${REDBEAR_KDE_SESSION_BACKEND:-auto}"
|
|
|
|
case "$requested" in
|
|
drm)
|
|
if [ -z "${KWIN_DRM_DEVICES:-}" ] && [ -e /scheme/drm/card0 ]; then
|
|
export KWIN_DRM_DEVICES=/scheme/drm/card0
|
|
fi
|
|
if [ -n "${KWIN_DRM_DEVICES:-}" ]; then
|
|
kwin_mode="drm"
|
|
else
|
|
kwin_mode="virtual"
|
|
fi
|
|
;;
|
|
virtual)
|
|
kwin_mode="virtual"
|
|
;;
|
|
auto|"")
|
|
if [ -n "${KWIN_DRM_DEVICES:-}" ]; then
|
|
kwin_mode="drm"
|
|
elif [ -e /scheme/drm/card0 ]; then
|
|
export KWIN_DRM_DEVICES=/scheme/drm/card0
|
|
kwin_mode="drm"
|
|
else
|
|
kwin_mode="virtual"
|
|
fi
|
|
;;
|
|
*)
|
|
kwin_mode="virtual"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
set_kwin_mode
|
|
|
|
if [ -z "${DBUS_SESSION_BUS_ADDRESS:-}" ] && command -v dbus-launch >/dev/null 2>&1; then
|
|
eval "$(dbus-launch --sh-syntax)"
|
|
fi
|
|
|
|
write_session_environment() {
|
|
{
|
|
printf 'DBUS_SESSION_BUS_ADDRESS=%s\n' "${DBUS_SESSION_BUS_ADDRESS:-}"
|
|
printf 'DESKTOP_SESSION=%s\n' "$DESKTOP_SESSION"
|
|
printf 'KDE_FULL_SESSION=%s\n' "$KDE_FULL_SESSION"
|
|
printf 'KDE_SESSION_VERSION=%s\n' "$KDE_SESSION_VERSION"
|
|
printf 'KWIN_DRM_DEVICES=%s\n' "${KWIN_DRM_DEVICES:-}"
|
|
printf 'KWIN_MODE=%s\n' "$kwin_mode"
|
|
printf 'QML2_IMPORT_PATH=%s\n' "$QML2_IMPORT_PATH"
|
|
printf 'QT_PLUGIN_PATH=%s\n' "$QT_PLUGIN_PATH"
|
|
printf 'QT_QPA_PLATFORM=%s\n' "$QT_QPA_PLATFORM"
|
|
printf 'QT_QPA_PLATFORM_PLUGIN_PATH=%s\n' "$QT_QPA_PLATFORM_PLUGIN_PATH"
|
|
printf 'SEATD_SOCK=%s\n' "$SEATD_SOCK"
|
|
printf 'SESSION_STATE_DIR=%s\n' "$session_state_dir"
|
|
printf 'WAYLAND_DISPLAY=%s\n' "$WAYLAND_DISPLAY"
|
|
printf 'XDG_CURRENT_DESKTOP=%s\n' "$XDG_CURRENT_DESKTOP"
|
|
printf 'XDG_RUNTIME_DIR=%s\n' "$XDG_RUNTIME_DIR"
|
|
printf 'XDG_SESSION_DESKTOP=%s\n' "$XDG_SESSION_DESKTOP"
|
|
printf 'XDG_SESSION_ID=%s\n' "$XDG_SESSION_ID"
|
|
printf 'XDG_SESSION_TYPE=%s\n' "$XDG_SESSION_TYPE"
|
|
printf 'XKB_CONFIG_ROOT=%s\n' "$XKB_CONFIG_ROOT"
|
|
} > "$session_env_file"
|
|
chmod 600 "$session_env_file" 2>/dev/null || true
|
|
}
|
|
|
|
write_session_environment
|
|
|
|
if command -v dbus-update-activation-environment >/dev/null 2>&1; then
|
|
dbus-update-activation-environment \
|
|
DBUS_SESSION_BUS_ADDRESS \
|
|
DBUS_SESSION_BUS_PID \
|
|
DESKTOP_SESSION \
|
|
KDE_FULL_SESSION \
|
|
KDE_SESSION_VERSION \
|
|
KWIN_DRM_DEVICES \
|
|
QML2_IMPORT_PATH \
|
|
QT_PLUGIN_PATH \
|
|
QT_QPA_PLATFORM \
|
|
QT_QPA_PLATFORM_PLUGIN_PATH \
|
|
WAYLAND_DISPLAY \
|
|
XDG_CURRENT_DESKTOP \
|
|
XDG_RUNTIME_DIR \
|
|
XDG_SESSION_DESKTOP \
|
|
XDG_SESSION_ID \
|
|
XDG_SESSION_TYPE \
|
|
XKB_CONFIG_ROOT \
|
|
XCURSOR_THEME
|
|
fi
|
|
|
|
wait_for_wayland_socket() {
|
|
local socket_path="$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY"
|
|
local attempts=0
|
|
|
|
while [ "$attempts" -lt 40 ]; do
|
|
if [ -S "$socket_path" ] || [ -e "$socket_path" ]; then
|
|
return 0
|
|
fi
|
|
if [ -n "$kwin_pid" ] && ! kill -0 "$kwin_pid" 2>/dev/null; then
|
|
return 1
|
|
fi
|
|
attempts=$((attempts + 1))
|
|
sleep 1
|
|
done
|
|
|
|
return 1
|
|
}
|
|
|
|
mark_validation_success() {
|
|
if [ -e "$VALIDATION_REQUEST" ]; then
|
|
: > "$VALIDATION_SUCCESS" 2>/dev/null || true
|
|
fi
|
|
}
|
|
|
|
validation_requested() {
|
|
[ -e "$VALIDATION_REQUEST" ]
|
|
}
|
|
|
|
launch_optional_component() {
|
|
local program="$1"
|
|
local ready_marker="$2"
|
|
|
|
if ! command -v "$program" >/dev/null 2>&1; then
|
|
return 0
|
|
fi
|
|
|
|
# kded6 is a D-Bus daemon with no GUI requirement.
|
|
# Force offscreen QPA to avoid the Qt6 Wayland page-fault crash at null+8.
|
|
if [ "$program" = "kded6" ]; then
|
|
QT_QPA_PLATFORM=offscreen "$program" &
|
|
else
|
|
"$program" &
|
|
fi
|
|
local pid=$!
|
|
optional_pids+=("$pid")
|
|
|
|
if [ -n "$ready_marker" ]; then
|
|
sleep 1
|
|
if kill -0 "$pid" 2>/dev/null; then
|
|
: > "$ready_marker"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
kwin_args=()
|
|
if [ "$kwin_mode" = "drm" ]; then
|
|
kwin_args+=(--drm)
|
|
else
|
|
kwin_args+=(--virtual)
|
|
fi
|
|
|
|
redbear-compositor "${kwin_args[@]}" &
|
|
kwin_pid=$!
|
|
|
|
if ! wait_for_wayland_socket; then
|
|
printf '%s\n' "redbear-kde-session: redbear-compositor failed to expose $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" >&2
|
|
exit 1
|
|
fi
|
|
|
|
: > "$session_ready_file"
|
|
mark_validation_success
|
|
|
|
if validation_requested; then
|
|
# Bounded validation mode: once the compositor exposed a real Wayland socket and
|
|
# the session marker was written, keep the session alive briefly so the checker can
|
|
# observe startup, then exit cleanly to let greeterd return to greeter_ready.
|
|
sleep 2
|
|
exit 0
|
|
fi
|
|
|
|
launch_optional_component kded6 ""
|
|
launch_optional_component redbear-statusnotifierwatcher ""
|
|
launch_optional_component plasmashell "$panel_ready_file"
|
|
|
|
wait "$kwin_pid"
|