Bump to v4.1 and add §16 documenting the round-2 fixes verified during
the doc-cleanup phase. Each finding cites exact paths and distinguishes
working-tree present from runtime-proven, following the §15 evidence
discipline.
G1. StatusNotifierWatcher — sender validation, owner-keyed registry,
lifecycle purging, bounded entries (APPLIED, 22 tests)
Honesty flag: the const BUS_NAME remains
"org.freedesktop.StatusNotifierWatcher" — only the recipe.toml
comment was updated to reference org.kde. The actual well-known
name change was NOT applied.
G2. redbear-notifications — sender-validated InvokeAction
NotificationRecord stores { owner, action_keys }. InvokeAction
returns fdo::Result<()> with three-condition validate_invoke
(id known, caller == owner, action_key declared).
G3. redbear-wifictl — NmState enum 0..70 + OwnedObjectPath types
New NmState enum covers Unknown..ConnectedGlobal. Root state()
maps NmDeviceState via from_device_state(). All NM interface
methods now return OwnedObjectPath via try_path() helper.
G4. redbear-sessiond — host-safe Can* test
can_methods_return_na now detects host vs Redox target via
kstop_writable() and asserts the correct expected value. No
behavioral change in the production path.
G5. redbear-statusnotifierwatcher — comprehensive sender tracking
and purge-on-disconnect (covered in G1 detail).
Also corrects two stale inline entries:
- §5.1 service-name table now notes 22 tests (vs prior 12)
- §3.1 redbear-statusnotifierwatcher entry expanded with round-2
scope per the G1 changes.
Verified against committed HEAD (1dc5b0dcb0): 22 statusnotifierwatcher
tests pass; 16 notifications tests pass; 35 wifictl tests pass;
52 sessiond tests pass.
98 KiB
Red Bear OS D-Bus Integration Plan
Implementation status (2026-07-26): All DBUS plan code artifacts are build-verified. Phase 3 DRM-compositor gates (PauseDevice/ResumeDevice emission, PrepareForSleep emission, dynamic device enumeration) are now structurally complete. Phase 4 re-enablement progress: 20/24 KF6 frameworks have USE_DBUS=ON. redbear-polkit v0.2 now implements real authorization (subject UID extraction, * / @group / !uid / !@group policy syntax, default-deny for unknown actions). redbear-udisks v0.2 now has working Mount / Unmount methods (fork+exec the appropriate filesystem daemon, SIGTERM to unmount, MountPoints / IdType properties). redbear-notifications v0.2 now emits the ActionInvoked signal via the new InvokeAction method. redbear-upower v0.2 exposes additional UPower Device properties (TimeToFull, TimeToEmpty, Energy, EnergyRate, BatteryLevel, PowerSupply, Serial); 7 unit tests cover the level enum. redbear-statusnotifierwatcher v0.2 has 12 unit tests covering the full D-Bus surface: RegisterStatusNotifierItem / RegisterStatusNotifierHost (signal-emitting) and UnregisterStatusNotifierItem / UnregisterStatusNotifierHost (previously stubbed), plus the StatusNotifierHostRegistered signal that the spec requires; 12 unit tests. redbear-sessiond is now host-buildable after fixing a RefCell → Arc<Mutex> Send/Sync issue and replacing the host-incompatible libredox::call::kill with the portable libc::kill; 32 unit tests pass. kf6-kwallet build now enables the kwalletd6 daemon binary (added KF6ColorScheme / KF6Crash / KF6DBusAddons / KF6GuiAddons / KF6Notifications / KF6WidgetsAddons to the dependency list, removed BUILD_KWALLETD=OFF, added a kwalletd6-wrapper.sh that disables the Wayland QPA on Redox; the kwalletd CMakeLists find_package(Qca-qt6 REQUIRED 2.3.1) is demoted to optional via sed because Qca-qt6 is not packaged in Red Bear OS yet). polkit-qt6-1 (PolkitQt6-1) is now packaged from the upstream 0.200.0 tarball, giving kf6-kauth a real Qt6 binding for the org.freedesktop.PolicyKit1 D-Bus API. kf6-kauth now uses the polkit-1 backend (-DKAUTH_BACKEND_NAME=POLKITQT6-1 -DKAUTH_HELPER_BACKEND_NAME=POLKITQT6-1) instead of the prior FAKE backend; it links against the freshly-built PolkitQt6-1, which talks to the redbear-polkit D-Bus daemon for real authorization. kf6-kded6 now builds the kded6 daemon binary (v4.0); the recipe wraps it with offscreen QPA. kf6-kglobalaccel now also builds the kglobalacceld5 daemon binary (v4.0); the recipe wraps it with offscreen QPA. The remaining items are runtime validation gates requiring QEMU, plus the Phase 4 surface only has kf6-kwallet's kwalletd binary remaining.
Version: 4.1 — 2026-07-27
Status: Active plan aligned with desktop path v6.0 (2026-07-26); §16 round-2 review appended 2026-07-27
Scope: Full D-Bus infrastructure for KDE Plasma 6 on Wayland, tightly integrated with Redox scheme IPC
Parent plan: local/docs/CONSOLE-TO-KDE-DESKTOP-PLAN.md (v6.0, 2026-07-26)
1. Executive Summary
D-Bus is mandatory infrastructure for KDE Plasma 6 — not optional, not deferrable. KDE services, KWin, plasmashell, and virtually every KF6 framework communicate over D-Bus at runtime.
Red Bear OS already has D-Bus 1.16.2 building with a 24-line redox.patch, the system bus wired
in redbear-full profile (historical redbear-kde name retired), and QtDBus enabled in qtbase. This is a solid
foundation, but it is only the transport layer. What's missing is the service layer — the
D-Bus services that KDE actually expects to talk to.
This plan defines a Redox-native D-Bus service architecture built on three decisions:
-
Use
dbus-daemon(reference implementation), notdbus-broker. It works without systemd, supports traditional.servicefile activation, and is battle-tested on non-systemd OSes (Alpine, Void, Gentoo/OpenRC). -
Build
redbear-sessiond— a small Rust daemon (usingzbus) that exposes the boundedorg.freedesktop.login1surface KWin already expects, plus a few higher-level manager helpers (GetUser,ActivateSessionOnSeat, lock/unlock/terminate helpers) that broader KDE session plumbing can call without forcing Red Bear into an elogind-sized reimplementation. Not elogind (too Linux-shaped), not ConsoleKit2 (legacy), but a targeted login1-compatible service backed by Redox's native seat/device model. -
Keep schemes and D-Bus separate. Schemes are the native resource plane. D-Bus is the desktop compatibility plane. Only add D-Bus facades when there is a real published freedesktop contract worth matching (
login1, laterNetworkManager,UPower,UDisks2).
Minimum viable D-Bus stack for KWin: system bus + session bus + redbear-sessiond with
login1 subset. No polkit, no UPower, no udisks2, no NetworkManager required for first KWin
compositor bring-up.
2. Architecture Principles
2.1 Schemes = Native Resource Plane, D-Bus = Desktop Compatibility Plane
┌─────────────────────────────────────────────────────────────────────┐
│ KDE Plasma / KWin / KF6 │
│ (speaks D-Bus, expects freedesktop contracts) │
├─────────────────────────────────────────────────────────────────────┤
│ D-Bus Compatibility Services │
│ redbear-sessiond (login1) redbear-notifications redbear-polkit│
│ (zbus-based Rust daemons, translating D-Bus ↔ scheme calls) │
├─────────────────────────────────────────────────────────────────────┤
│ dbus-daemon (system bus + session bus) │
│ Classic .service activation, XML policies │
├─────────────────────────────────────────────────────────────────────┤
│ Redox Schemes (native IPC) │
│ scheme:pci scheme:input scheme:drm scheme:net scheme:acpi │
│ evdevd udev-shim redox-drm netd acpid │
└─────────────────────────────────────────────────────────────────────┘
D-Bus services wrap scheme resources into freedesktop-compatible contracts. They do not replace or mirror schemes. Each D-Bus service holds only the scheme handles it needs, and clients never get raw scheme access through D-Bus.
2.2 Use Existing Contracts, Don't Invent New Ones
| Namespace | Use For |
|---|---|
org.freedesktop.login1 |
Session/seat/device tracking — KWin expects this |
org.freedesktop.Notifications |
Desktop notifications — kf6-knotifications expects this |
org.freedesktop.NetworkManager |
Deferred — not in current Red Bear OS scope |
org.freedesktop.UPower |
Power management — PowerDevil expects this |
org.freedesktop.UDisks2 |
Storage management — Solid/udisks backend expects this |
org.freedesktop.PolicyKit1 |
Privileged actions — KAuth expects this |
org.kde.* |
KDE-specific services — KWin, plasmashell, kglobalaccel, kded6 |
org.redbear.* |
Red Bear-specific services that don't match any freedesktop contract |
2.3 No Generic Scheme→D-Bus Bridge
Do NOT build a universal translator that mirrors every scheme as a D-Bus object. Each D-Bus compatibility service is hand-written for a specific freedesktop contract, backed by the specific schemes it needs. This keeps the architecture honest and avoids a leaky abstraction.
2.4 Rust-Native for New Services, C for Existing Daemons
| Component | Implementation | Why |
|---|---|---|
dbus-daemon |
C (freedesktop upstream) | Battle-tested, minimal redox.patch, no reason to rewrite |
libdbus-1 |
C (part of dbus package) | Required by QtDBus, kf6-kdbusaddons |
redbear-sessiond |
Rust + zbus |
New code, Rust-native OS, async, strong typing |
| Future compat daemons | Rust + zbus |
Same reasons as redbear-sessiond |
| KDE apps (KWin, plasmashell) | C++ via QtDBus | Upstream KDE code, not our concern |
3. Current State Assessment
3.1 What Exists and Works
| Component | Location | Status | Detail |
|---|---|---|---|
| D-Bus 1.16.2 daemon | local/recipes/system/dbus/ |
✅ Builds, bounded runtime | 24-line redox.patch (epoll guard + socketpair fix), meson build with systemd disabled; dbus-root-uid.patch now wired into recipe |
| libdbus-1 | Part of dbus package | ✅ Builds | libdbus-1.so.3.38.3 staged, pkgconfig and cmake files present |
| QtDBus | local/recipes/qt/qtbase/ |
✅ Enabled | FEATURE_dbus=ON for target build, Qt6DBus module present |
| kf6-kdbusaddons | local/recipes/kde/kf6-kdbusaddons/ |
✅ Builds | KF6 D-Bus convenience wrappers, provides qdbus tool integration |
| D-Bus system bus | config/redbear-full.toml |
✅ Wired | 12_dbus.service launches dbus-daemon --system, messagebus user (uid=100), /var/lib/dbus + /run/dbus directories |
| D-Bus session bus | local/recipes/system/redbear-greeter/source/redbear-session-launch |
✅ Scripted | redbear-session-launch launches dbus-launch --sh-syntax before KWin |
| seatd | config/redbear-full.toml |
✅ Wired | 13_seatd.service, LIBSEAT_BACKEND=seatd, SEATD_SOCK=/run/seatd.sock |
| kf6-kservice | local/recipes/kde/kf6-kservice/ |
✅ Builds | Depends on kf6-kdbusaddons |
| kf6-kglobalaccel | local/recipes/kde/kf6-kglobalaccel/ |
✅ Builds | Depends on kf6-kdbusaddons |
| Session activation scaffolds | local/recipes/system/redbear-dbus-services/ |
✅ Staged | Session .service files now cover core freedesktop services and pulseaudio; the 5 wlroots-based KDE daemons (kded6, kglobalaccel, ActivityManager, JobViewServer, ksmserver) were removed in W2 (honest-absence, 2026-07-26). They will be re-added when the daemons are built. |
| KWin (D-Bus) | local/recipes/kde/kwin/ |
✅ USE_DBUS=ON | Registers org.kde.KWin on session bus |
redbear-sessiond PauseDevice/ResumeDevice emission |
local/recipes/system/redbear-sessiond/source/src/session.rs |
✅ done (v3.1) | Signals emitted on take_device / release_device; fresh FD re-opened on resume |
redbear-sessiond PrepareForSleep emission |
local/recipes/system/redbear-sessiond/source/src/acpi_watcher.rs |
✅ done (v3.1) | CheckSleep ACPI verb polled; before=true on suspend, before=false on resume |
| Dynamic device enumeration | local/recipes/system/redbear-sessiond/source/src/device_map.rs |
✅ done (v3.1) | No hardcoded entries; lazy filesystem scan + cache + refresh(); /scheme/drm/, /dev/input/, /dev/fb*, and special char-devs |
| redbear-polkit v0.2 (comprehensive authorization) | local/recipes/system/redbear-polkit/source/src/main.rs |
✅ done (v3.2) | Subject UID extraction (real authorization, no longer always-permit); policy syntax uid, @group, *, !uid, !@group; default-deny for unknown actions; 13 unit tests cover all paths |
| redbear-polkit policy file | config/redbear-full.toml, config/redbear-mini.toml |
✅ done (v3.2) | /etc/polkit-1/policy.toml staged with comprehensive syntax examples (power, storage, network) |
redbear-udisks Mount / Unmount |
local/recipes/system/redbear-udisks/source/src/{inventory.rs,interfaces.rs,mount.rs} |
✅ done (v3.3) | Detects ext4/vfat by magic number; fork()+exec()s the appropriate filesystem daemon; stores child PID in MountState; Unmount sends SIGTERM. 9 unit tests cover the detection paths. |
redbear-notifications ActionInvoked |
local/recipes/system/redbear-notifications/source/src/main.rs |
✅ done (v3.3) | InvokeAction(id, action_key) method emits the ActionInvoked signal. ServerVersion bumped to 0.2.0. |
| redbear-statusnotifierwatcher tests | local/recipes/system/redbear-statusnotifierwatcher/source/src/main.rs |
✅ done (v3.3, expanded round 2) | 22 unit tests cover item/host registration (signal-emitting), unregistration (owner-validated), idempotency, snapshot correctness, cross-owner enforcement, NameOwnerChanged purge, input validation, and bounded eviction. (Test count updated 2026-07-27 round 2: see §16 G1.) |
3.2 What Exists But Is Incomplete
| Component | Location | Status | Gap |
|---|---|---|---|
| elogind | (not in tree) | ✅ Rejected upstream | elogind needs libeudev + libcap, too Linux-shaped for Redox; redbear-sessiond is the chosen strategy |
| kf6-knotifications | local/recipes/kde/kf6-knotifications/ |
✅ D-Bus ON (v0.3 daemon) | Built with -DUSE_DBUS=ON; redbear-notifications v0.3 emits ActionInvoked |
| kf6-kio | local/recipes/kde/kf6-kio/ |
✅ D-Bus ON (v3.1) | Built with -DUSE_DBUS=ON; Qt6Network linked for KIOGui/KIOWidgets |
| kf6-solid | local/recipes/kde/kf6-solid/ |
✅ D-Bus ON (v3.1) | Built with -DUSE_DBUS=ON; UPower / UDisks2 / login1 backends enabled |
| kf6-kwallet | local/recipes/kde/kf6-kwallet/ |
⚠️ BUILD_KWALLETD=OFF |
Real API-only cmake build (no kwalletd daemon); kwalletd build is a separate task |
| plasma-workspace | local/recipes/kde/plasma-workspace/ |
✅ Enabled in redbear-full | Explicit dbus dep; sub-services activation files staged; runtime proof requires QEMU |
3.3 What Ships Today (Scaffolds and Deferred Items)
| Component | Namespace | Purpose | KDE Consumer |
|---|---|---|---|
| Session tracker | org.freedesktop.login1 |
Session/seat/device brokering scaffold | KWin (hard requirement for DRM/libinput) |
| Notification daemon | org.freedesktop.Notifications |
Notification service scaffold | kf6-knotifications |
| Polkit | org.freedesktop.PolicyKit1 |
Authorization scaffold (always-permit) | KAuth |
| UPower | org.freedesktop.UPower |
Provisional ACPI-backed power service; current backing power surface is provisionally bounded; broader ACPI validation requires QEMU/hardware | kf6-solid, PowerDevil |
| UDisks2 | org.freedesktop.UDisks2 |
Bounded real disk.* / partition enumeration |
kf6-solid |
| D-Bus service files | /usr/share/dbus-1/ |
Activation is staged and shipped for the current scaffold services; the 5 wlroots-based KDE session daemons (kded6, kglobalaccel, ActivityManager, JobViewServer, ksmserver) were removed in W2 (honest-absence, 2026-07-26) and will be re-added when the daemons are built. Note (2026-07-27): the org.freedesktop.StatusNotifierWatcher.service activation file IS staged but points to /usr/bin/redbear-statusnotifierwatcher, which is absent from every redbear-* config — the recipe is build-verified but not wired into any image target |
All D-Bus services |
| D-Bus policy files | /etc/dbus-1/ |
Policy is staged and shipped for the current scaffold services | All D-Bus services |
| zbus crate marker | local/recipes/libs/zbus/ |
Build-ordering marker; actual zbus crate is fetched by downstream Cargo builds | Future Rust D-Bus services |
Deferred and not shipped in the current implementation cycle:
org.freedesktop.NetworkManager/redbear-nm— Red Bear OS usesredbear-netctlfor now
4. Gap Analysis
4.1 Critical Path Gaps (blocks KWin compositor)
KWin needs:
dbus-daemon --system ✅ exists, wired
dbus-daemon --session ✅ exists, wired in redbear-session-launch
org.freedesktop.login1 ✅ scaffold exists — session/device brokering implemented minimally
org.kde.KWin (self-register) ✅ KWin does this itself (dbusinterface.cpp)
The single critical runtime-risk area is org.freedesktop.login1. KWin's session_logind.cpp calls
TakeDevice(), ReleaseDevice(), TakeControl(), and listens for PauseDevice/ResumeDevice
signals. Without this, KWin cannot take ownership of DRM/input devices through the freedesktop
session protocol.
KWin's session selection chain is: logind → ConsoleKit → Noop. The Noop backend returns -1
from openRestricted() — meaning it can start but cannot manage real devices.
4.2 Desktop Session Gaps (blocks plasma-workspace)
plasma-workspace needs:
org.kde.KWin ✅ KWin provides
org.kde.kglobalaccel ❌ activation file removed (honest absence) — daemon binary not yet built/runtime-validated
org.kde.kded6 ❌ activation file removed (honest absence) — daemon binary not yet built/runtime-validated
org.kde.plasmashell ✅ plasmashell provides (self-register)
org.kde.osdService ✅ plasmashell provides
org.freedesktop.Notifications ✅ scaffold exists — current daemon logs to stderr only
4.3 Full Desktop Gaps (blocks complete KDE Plasma)
Complete Plasma needs (after re-enabling disabled components):
org.freedesktop.UPower ⚠️ service exists, but ACPI-backed power reporting is still provisional and needs Wave 3 closure in the ACPI plan before kf6-solid can rely on it
org.freedesktop.UDisks2 ✅ bounded real enumeration exists — build-verified; supplementary QEMU runtime validation for kf6-solid
org.freedesktop.NetworkManager ⏸️ DEFERRED — Red Bear OS uses redbear-netctl for now
org.freedesktop.PolicyKit1 ✅ v0.3 — real authorization (subject UID extraction, comprehensive policy syntax, default-deny); kf6-kauth now uses the polkit-1 backend (PolkitQt6-1) to bind to this contract
org.freedesktop.StatusNotifierWatcher ⚠️ activation file staged in redbear-dbus-services, but recipe NOT in any config (binary absent from image); watcher source build-verified in isolation; see §15 Review Finding F5
org.kde.JobViewServer ❌ activation file removed (honest absence) — kuiserver binary not yet built
org.kde.ksmserver ❌ activation file removed (honest absence) — session manager binary not yet built
org.kde.ActivityManager ❌ activation file removed (honest absence) — activity manager binary not yet built
org.freedesktop.ScreenSaver: deferred (not on critical path) — screen locking
4.4 Build System Gaps
| Gap | Detail |
|---|---|
zbus recipe is only a marker |
Build-ordering marker exists; actual Rust crate comes from downstream Cargo resolution |
| D-Bus service activation is scaffolded | /usr/share/dbus-1/system-services/ and session-services/ are staged for current services |
| D-Bus policy configuration is scaffolded | /etc/dbus-1/system.d/ XML policy files are staged for current services |
| Activation coverage: system services + KDE session daemons staged (.service files present); screen-lock deferred (non-critical) | |
| kf6-knotifications now D-Bus enabled | Enabled against a minimal notification daemon scaffold |
| kf6-solid D-Bus disabled | Must re-enable after UPower/udisks2 backends exist |
| kf6-kio D-Bus disabled | Must re-enable for full KIO functionality |
5. Architecture Design
5.1 Overall Stack
┌──────────────────────────────────────────────────────────────────────────┐
│ KDE Plasma 6 Desktop Session │
│ plasmashell, kwin_wayland, kded6, kglobalaccel, plasma applets │
├──────────────────────────────────────────────────────────────────────────┤
│ Session Bus (per-user) │
│ Started by: redbear-session-launch via dbus-launch or dbus-run-session │
│ Policy: /etc/dbus-1/session.conf │
│ Services: /usr/share/dbus-1/session-services/ │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ org.kde.KWin (KWin self-registers) │ │
│ │ org.kde.plasmashell (plasmashell self-registers) │ │
│ │ org.kde.kglobalaccel (daemon NOT built — activation removed) │ │
│ │ org.kde.kded6 (daemon NOT built — activation removed) │ │
│ │ org.kde.ActivityManager (daemon NOT built — activation removed) │ │
│ │ org.kde.JobViewServer (daemon NOT built — activation removed) │ │
│ │ org.kde.ksmserver (daemon NOT built — activation removed) │ │
│ │ org.freedesktop.Notifications (redbear-notifications) │ │
│ │ org.freedesktop.StatusNotifierWatcher (redbear-statusnotifier)│ │
│ └──────────────────────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────────────────────────┤
│ System Bus (machine-global) │
│ Started by: Redox init (12_dbus.service) │
│ Policy: /etc/dbus-1/system.conf + system.d/*.conf │
│ Services: /usr/share/dbus-1/system-services/ │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ org.freedesktop.login1 (redbear-sessiond) │ │
│ │ org.freedesktop.DBus (dbus-daemon itself) │ │
│ │ [Phase 4+] org.freedesktop.UPower (redbear-upower) │ │
│ │ [Phase 4+] org.freedesktop.UDisks2 (redbear-udisks) │ │
│ │ [deferred] org.freedesktop.NetworkManager (not in scope) │ │
│ │ [Phase 4+] org.freedesktop.PolicyKit1 (redbear-polkit) │ │
│ └──────────────────────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────────────────────────┤
│ dbus-daemon 1.16.2 │
│ C reference implementation, redox.patch for epoll + socketpair │
│ systemd disabled, legacy GUI autolaunch disabled │
│ Classic .service file activation │
├──────────────────────────────────────────────────────────────────────────┤
│ Redox Schemes (native IPC) │
│ scheme:input → evdevd → /dev/input/eventX │
│ scheme:drm → redox-drm → DRM/KMS │
│ scheme:pci → driver-manager → PCI device access │
│ scheme:net → netd → network interfaces │
│ scheme:firmware → firmware-loader → GPU blobs │
│ scheme:acpi → acpid → ACPI/DMI data │
│ scheme:seat → seatd → seat management (libseat API) │
└──────────────────────────────────────────────────────────────────────────┘
5.2 D-Bus Service Lifecycle
Boot:
1. Redox init starts 12_dbus.service → dbus-daemon --system
2. Redox init starts 13_redbear-sessiond.service → redbear-sessiond
(registers org.freedesktop.login1 on system bus)
3. Redox init starts 13_seatd.service → seatd
Session launch (redbear-session-launch):
4. dbus-daemon --system already running
5. eval $(dbus-launch --sh-syntax) → session bus started
6. export DBUS_SESSION_BUS_ADDRESS, XDG_SESSION_ID, XDG_SEAT, XDG_RUNTIME_DIR
7. redbear-compositor --drm → launches KWin on the session bus and owns the Wayland socket lifecycle for the current Red Bear session path
8. [later] plasmashell → registers org.kde.plasmashell on session bus
5.3 Service Activation Strategy
| Service Type | Activation Method | Why |
|---|---|---|
| System bus core (login1) | Redox init | Must be running before any desktop session |
| System bus compat (UPower, NM) | Redox init or D-Bus activation | Can be started lazily, but init is simpler |
| Session bus KDE services (kglobalaccel, kded6) | D-Bus activation (classic .service files) |
KDE expects this, standard pattern |
| Session bus KDE shell (KWin, plasmashell) | Explicit launch in redbear-session-launch |
Must start in specific order with env vars |
| Session bus compat (notifications, tray) | D-Bus activation | Standard freedesktop pattern |
6. Component Specifications
6.1 redbear-sessiond — Session/Seat/Device Broker
Purpose: Provides the org.freedesktop.login1 D-Bus interface that KWin requires for
device access control, session management, and power signaling.
Implementation: Rust binary, uses zbus for D-Bus, backed by Redox scheme IPC.
Bus: System bus
Bus name: org.freedesktop.login1
D-Bus Interfaces
/org/freedesktop/login1 — Manager
| Interface | Method/Signal | Signature | Description |
|---|---|---|---|
org.freedesktop.login1.Manager |
GetSession |
s → o |
Returns session object path by ID |
GetUser |
u → o |
Returns the current user object path for the bounded active session owner | |
GetUserByPID |
u → o |
Returns the current user object path for the bounded active session surface | |
ListSessions |
→ a(susso) |
Lists all active sessions | |
GetSeat |
s → o |
Returns seat object path | |
ActivateSessionOnSeat |
ss → |
Marks the bounded session active on the requested seat | |
LockSessions / UnlockSessions |
→ |
Updates the bounded session lock hint for KDE session plumbing | |
TerminateUser |
u → |
Marks the bounded active user session closing | |
signal PrepareForSleep |
b |
Emitted before/after sleep (false=resume, true=suspend) | |
signal PrepareForShutdown |
b |
Emitted before/after shutdown | |
org.freedesktop.DBus.Properties |
Get |
ss → v |
Property access |
GetAll |
s → a{sv} |
All properties |
/org/freedesktop/login1/session/c1 — Session
| Interface | Method/Signal | Signature | Description |
|---|---|---|---|
org.freedesktop.login1.Session |
Activate |
→ |
Activate this session |
TakeControl |
b → |
Take exclusive control of session devices | |
ReleaseControl |
→ |
Release device control | |
TakeDevice |
uu → h |
Take device by major/minor (returns fd) | |
ReleaseDevice |
uu → |
Release device by major/minor | |
PauseDeviceComplete |
uu → |
Acknowledge device pause | |
property Active |
b |
Is this session active | |
property Seat |
(so) |
Seat this session belongs to | |
property User |
(uo) |
User info | |
property Type |
s |
Session type (e.g. "wayland") | |
signal PauseDevice |
uus |
Device paused (major, minor, type) | |
signal ResumeDevice |
uuh |
Device resumed (major, minor, fd) |
/org/freedesktop/login1/seat/seat0 — Seat
| Interface | Method/Signal | Signature | Description |
|---|---|---|---|
org.freedesktop.login1.Seat |
SwitchTo |
u → |
Switch to VT number |
property ActiveSession |
(so) |
Currently active session | |
property Sessions |
a(so) |
All sessions on this seat |
Scheme Backing
redbear-sessiond translates login1 D-Bus calls into Redox scheme operations:
| login1 Method | Redox Backend |
|---|---|
TakeDevice(major, minor) |
Opens the corresponding scheme path (e.g., /scheme/drm/card0 for DRM, /dev/input/eventX for input) using udev-shim's device enumeration to resolve major/minor → scheme path |
ReleaseDevice(major, minor) |
Closes the scheme file descriptor |
TakeControl(force) |
Records compositor ownership; no kernel-level operation needed (seatd already provides seat arbitration) |
Activate() |
Sets session as active; signals to compositor via D-Bus |
SwitchTo(vt) |
Delegates to inputd -A <vt> (existing Redox VT switching) |
PrepareForSleep |
Future/conditional: only available once ACPI sleep eventing exists; currently a known gap in the ACPI stack |
PrepareForShutdown |
Generated from the current ACPI-backed shutdown signal path via scheme:acpi / kstop |
Device Number Mapping
KWin identifies devices by Linux major/minor numbers. Red Bear OS must maintain a stable
mapping from (major, minor) → scheme path:
| Device Class | Major | Minor Source | Scheme Path |
|---|---|---|---|
| DRM/GPU | 226 (Linux DRM major) | card index (0, 1...) | /scheme/drm/card0 |
| Input (evdev) | 13 (Linux input major) | event index (64+) | /dev/input/eventX (via evdevd) |
| Framebuffer | 29 (Linux fb major) | fb index (0, 1...) | /dev/fbX |
The udev-shim daemon already maintains a device database that maps scheme paths to
traditional /dev/ paths with major/minor numbers. redbear-sessiond should query this
database rather than maintaining its own mapping.
Configuration
local/recipes/system/redbear-sessiond/
├── recipe.toml # cargo template, depends on dbus (for libdbus headers)
├── source/
│ ├── Cargo.toml # zbus + libredox + redox-syscall deps
│ └── src/
│ ├── main.rs # Daemon entry: fork, signal handling, D-Bus registration
│ ├── manager.rs # org.freedesktop.login1.Manager interface
│ ├── session.rs # org.freedesktop.login1.Session interface
│ ├── seat.rs # org.freedesktop.login1.Seat interface
│ ├── device_map.rs # major/minor → scheme path resolution (via udev-shim)
│ └── acpi_watcher.rs # current kstop-backed shutdown watcher; sleep signaling remains future-only until ACPI sleep eventing exists
6.2 D-Bus Service Activation Files
System Bus Service Files
Location: /usr/share/dbus-1/system-services/
org.freedesktop.login1.service:
[D-BUS Service]
Name=org.freedesktop.login1
Exec=/usr/bin/redbear-sessiond
User=root
SystemdService= # intentionally empty — no systemd
Session Bus Service Files
Location: /usr/share/dbus-1/session-services/
REMOVED (honest absence — daemons not built, Exec pointed to non-existent
binaries; will be re-added when the daemons are built/validated):
org.kde.kglobalaccel.service (Exec=/usr/bin/kglobalaccel)
org.kde.kded6.service (Exec=/usr/bin/kded6)
org.kde.ActivityManager.service (Exec=/usr/bin/kactivitymanagerd)
org.kde.JobViewServer.service (Exec=/usr/bin/kuiserver)
org.kde.ksmserver.service (Exec=/usr/bin/ksmserver)
STAGED (daemons built and validated):
org.freedesktop.Notifications.service:
[D-BUS Service]
Name=org.freedesktop.Notifications
Exec=/usr/bin/redbear-notifications
Recipe for Service Files
Create a redbear-dbus-services recipe that stages all activation files and policies:
local/recipes/system/redbear-dbus-services/
├── recipe.toml # template = "custom", no source tarball
└── files/
├── system-services/
│ └── org.freedesktop.login1.service
├── session-services/
│ └── org.freedesktop.Notifications.service
│ # (KDE daemon .service files removed — see §4.2/§4.3 gap analysis)
├── system.d/
│ ├── org.freedesktop.login1.conf
│ └── org.redbear.session.conf
└── session.d/
└── org.redbear.session.conf
6.3 D-Bus Policy Configuration
System Bus Policy (/etc/dbus-1/system.d/org.freedesktop.login1.conf)
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<policy user="root">
<allow own="org.freedesktop.login1"/>
<allow send_destination="org.freedesktop.login1"/>
<allow receive_sender="org.freedesktop.login1"/>
</policy>
<policy context="default">
<allow send_destination="org.freedesktop.login1"
send_interface="org.freedesktop.DBus.Introspectable"/>
<allow send_destination="org.freedesktop.login1"
send_interface="org.freedesktop.DBus.Properties"/>
<allow send_destination="org.freedesktop.login1"
send_interface="org.freedesktop.login1.Manager"/>
<allow send_destination="org.freedesktop.login1"
send_interface="org.freedesktop.login1.Session"/>
<allow send_destination="org.freedesktop.login1"
send_interface="org.freedesktop.login1.Seat"/>
<allow receive_sender="org.freedesktop.login1"/>
</policy>
</busconfig>
Session Bus Policy (/etc/dbus-1/session.d/org.redbear.session.conf)
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<policy context="default">
<allow own="org.kde.*"/>
<allow send_destination="org.kde.*"/>
<allow receive_sender="org.kde.*"/>
<allow own="org.freedesktop.Notifications"/>
<allow send_destination="org.freedesktop.Notifications"/>
<allow receive_sender="org.freedesktop.Notifications"/>
</policy>
</busconfig>
6.4 zbus Recipe
Add zbus as a recipe so it can be a build dependency for redbear-sessiond and future
Rust D-Bus services:
recipes/libs/zbus/ or local/recipes/libs/zbus/
├── recipe.toml # cargo template
└── source/
├── Cargo.toml # zbus + zvariant + zbus_names deps
└── src/
└── lib.rs # (upstream zbus crate)
Note: zbus is a pure Rust crate with no C dependencies. It uses async Rust I/O
(tokio or async-std) and UNIX domain sockets. On Redox, it will use the Redox event
system via syscall::scheme_read / scheme_write through the standard Rust std::os::unix
APIs, which relibc provides.
7. Phased Implementation
Phase DB-1: KWin Minimum Viable D-Bus (2–3 weeks)
Goal: KWin can start as Wayland compositor with a real session broker.
Work items:
⚠️ GROSS WARNING — DO NOT run
repo cook,repo fetch, ormake livedirectly. These bypass the canonical build pipeline (apply-patches.shpatch-linking + staleness handling + correct dependency ordering), which causes broken/missing patches and wasted rebuild time. ALWAYS build via./local/scripts/build-redbear.sh [--upstream] <config>(or the documentedmaketargets it drives). If you think you need a single-recipe cook, run the canonical wrapper — it does the right thing and is faster in the end.
| # | Task | Acceptance Criteria |
|---|---|---|
| 1.1 | Add zbus recipe to recipe tree |
make r.zbus succeeds, crate stages to sysroot |
| 1.2 | Implement redbear-sessiond with minimal login1 Manager + Session + Seat |
Daemon starts, registers org.freedesktop.login1 on system bus |
| 1.3 | Implement TakeDevice/ReleaseDevice via udev-shim device map |
KWin can request DRM and input devices through D-Bus |
| 1.4 | Implement TakeControl/ReleaseControl |
KWin can take exclusive session ownership |
| 1.5 | Create D-Bus policy files for login1 | Policy allows session compositor to call login1 methods |
| 1.6 | Create D-Bus activation .service file for login1 |
redbear-sessiond can be activated or init-started |
| 1.7 | Add redbear-sessiond to redbear-full.toml init services |
Service starts before KWin in boot sequence |
| 1.8 | Wire XDG_SESSION_ID, XDG_SEAT, XDG_RUNTIME_DIR in the KDE session launcher |
KWin sees a valid session environment |
| 1.9 | Validate: dbus-send --system --dest=org.freedesktop.login1 --print-reply /org/freedesktop/login1 org.freedesktop.login1.Manager.ListSessions |
Returns non-empty session list |
| 1.10 | Validate: dbus-send --session --dest=org.kde.KWin /KWin org.kde.KWin.supportInformation |
Returns non-empty KWin info string |
Exit criteria:
redbear-sessiond— binary present, service wired; runtime registration requires QEMU bootlogin1.Manager.ListSessions— implemented in sessiond; runtime validation requires QEMU- KWin
TakeDevice— DRM/input device methods structurally present; runtime requires QEMU with DRM - KWin D-Bus registration — reduced-feature real build provides the surface; runtime proof requires Qt6Quick/QML downstream validation
org.kde.KWin.supportInformation— structurally implemented; runtime proof requires real KWin- Bounded compositor-session survival — validation compositor path proven; real KWin runtime proof requires Qt6Quick/QML downstream validation
Dependencies: relibc eventfd/timerfd/signalfd (already built), evdevd, udev-shim, seatd
Phase DB-2: Desktop Session Services (2–3 weeks)
Goal: plasma-workspace can start with essential session services.
Work items:
| # | Task | Acceptance Criteria |
|---|---|---|
| 2.1 | Create redbear-dbus-services recipe with all session .service files |
Files staged to /usr/share/dbus-1/session-services/ |
| 2.2 | Ensure kglobalaccel launches and registers on session bus |
dbus-send --session --dest=org.kde.kglobalaccel ... succeeds |
| 2.3 | Ensure kded6 launches and registers on session bus |
dbus-send --session --dest=org.kde.kded6 ... succeeds |
| 2.4 | Implement redbear-notifications — minimal notification daemon |
Registers org.freedesktop.Notifications, can receive and display a notification |
| 2.5 | Re-enable D-Bus in kf6-knotifications (-DUSE_DBUS=ON) |
kf6-knotifications builds with D-Bus enabled |
| 2.6 | Validate plasmashell startup | plasmashell process starts, registers org.kde.plasmashell |
| 2.7 | Validate OSD service | org.kde.osdService responds to brightness/volume queries |
Exit criteria:
- kglobalaccel — activation file staged; runtime registration requires QEMU
- kded6 — activation file staged; runtime registration requires QEMU
org.freedesktop.Notifications— service files present; runtime Notify() requires QEMU- kf6-knotifications — builds with D-Bus enabled (USE_DBUS=ON in recipe)
- plasmashell — plasma-workspace enabled in config; runtime registration requires full Plasma session (gated on Qt6Quick + real KWin)
org.freedesktop.UPower— redbear-upower v0.2 (Changedsignal + new properties) — runtime validation requires QEMUorg.freedesktop.UDisks2— redbear-udisks v0.2 (device enumeration + Mount/Unmount) — runtime validation requires QEMU- kf6-solid — UPower/UDisks2 backends deferred; ACPI power surface validated within bounded proof
- Shutdown signal — login1 interface structurally present; sleep signal requires ACPI sleep eventing
org.freedesktop.PolicyKit1— deferred; not on critical path for minimal Plasma session- KAuth polkit backend — fake backend sufficient for bounded proof; real polkit deferred
Phase DB-5: Polish and Full Integration (ongoing)
Goal: Complete D-Bus coverage for full KDE Plasma desktop experience.
Work items:
| # | Task | Acceptance Criteria |
|---|---|---|
| 5.1 | Implement org.freedesktop.StatusNotifierWatcher for system tray |
System tray icons appear in Plasma panel |
| 5.2 | Implement org.kde.JobViewServer for job progress |
File copy/move operations show progress in Plasma |
| 5.3 | Implement org.kde.ksmserver for session management |
Logout/restart/shutdown work from Plasma menu |
| 5.4 | Implement org.freedesktop.ScreenSaver for screen locking |
Screen locks on timeout and manual lock |
| 5.5 | Enable kf6-kwallet in redbear-full (recipe exists in-tree) | KWallet stores and retrieves passwords |
| 5.6 | Re-enable D-Bus in kf6-kio | KIO uses D-Bus for service activation |
| 5.7 | Promote dbus recipe from WIP to production | Done — dbus is now at local/recipes/system/dbus/ with dbus-root-uid.patch wired in (v3.1) |
Dependencies: Phases DB-1 through DB-4 complete
8. Integration with Console-to-KDE Plan
This D-Bus plan maps directly onto the phases in CONSOLE-TO-KDE-DESKTOP-PLAN.md v6.0 (2026-07-26):
| Desktop Plan Phase | D-Bus Plan Phase | What D-Bus delivers |
|---|---|---|
| Phase 1: Runtime Substrate Validation | (no D-Bus work — substrate is below D-Bus) | — |
| Phase 2: Wayland Compositor Proof | DB-1: KWin MVP | login1 session broker, system/session bus validation |
| Phase 3: KWin Desktop Session | DB-1 (completion) + DB-2 (session services) | kglobalaccel, kded6, notifications, plasmashell D-Bus |
| Phase 4: KDE Plasma Session | DB-3 (hardware services) + DB-4 (network/policy) | UPower once the ACPI power surface is honest, udisks2, NM, polkit, full session |
| Phase 5: Hardware GPU Enablement | (D-Bus not on critical path for GPU) | login1 TakeDevice for GPU fd passing |
Modifications to Console-to-KDE Plan
The following updates should be applied to CONSOLE-TO-KDE-DESKTOP-PLAN.md:
Phase 2 — add D-Bus validation tasks:
| # | Task | Acceptance Criteria |
|---|---|---|
| 2.X | Validate D-Bus system bus lifecycle | dbus-daemon --system starts from init, /run/dbus/system_bus_socket exists, dbus-send --system --dest=org.freedesktop.DBus --print-reply /org/freedesktop/DBus org.freedesktop.DBus.ListNames returns a list including org.freedesktop.login1 |
| 2.X | Validate D-Bus session bus lifecycle | dbus-launch --sh-syntax sets DBUS_SESSION_BUS_ADDRESS, dbus-send --session --print-reply /org/freedesktop/DBus org.freedesktop.DBus.ListNames returns a non-empty list |
Phase 3 — update D-Bus task 3.4:
Replace the existing task 3.4 with:
| # | Task | Acceptance Criteria |
|---|---|---|
| 3.4 | Validate complete D-Bus session stack | org.freedesktop.login1.Manager.ListSessions returns valid data; org.kde.KWin.supportInformation returns non-empty string; kglobalaccel registered on session bus |
Phase 4 — add D-Bus service milestone:
| # | Task | Acceptance Criteria |
|---|---|---|
| 4.X | D-Bus hardware services operational | org.freedesktop.UPower and org.freedesktop.UDisks2 register on system bus; UPower consumer claims stay bounded until the ACPI power surface is validated |
| 4.X | D-Bus network service operational | Deferred — Red Bear OS uses redbear-netctl, not NetworkManager |
9. D-Bus Service Dependency Map
9.1 System Bus Services
org.freedesktop.DBus (dbus-daemon itself — always present)
│
├── org.freedesktop.login1 (redbear-sessiond)
│ ├── Depends on: scheme:acpi (for sleep/shutdown signals)
│ ├── Depends on: udev-shim (for device major/minor → scheme path mapping)
│ ├── Depends on: seatd (for seat arbitration)
│ ├── Consumed by: KWin (TakeDevice, TakeControl, PauseDevice, ResumeDevice)
│ └── Consumed by: kf6-solid (session properties)
│
├── [Phase DB-3] org.freedesktop.UPower (redbear-upower)
│ ├── Depends on: the current `/scheme/acpi/power` surface (still provisional until the ACPI plan's Wave 3 closes)
│ └── Consumed by: kf6-solid, PowerDevil
│
├── [Phase DB-3] org.freedesktop.UDisks2 (redbear-udisks)
│ ├── Depends on: udev-shim (for block device enumeration)
│ └── Consumed by: kf6-solid, dolphin, plasma-workspace
│
├── [Deferred] org.freedesktop.NetworkManager (not in current scope)
│ ├── Red Bear OS uses: redbear-netctl / redbear-wifictl
│ └── Revisit only if plasma-nm applet integration becomes a priority
│
└── [Phase DB-4] org.freedesktop.PolicyKit1 (redbear-polkit)
└── Consumed by: KAuth, privileged desktop actions
9.2 Session Bus Services
org.freedesktop.DBus (dbus-daemon — always present)
│
├── org.kde.KWin (KWin — self-registers)
│ ├── Object: /KWin
│ ├── Interfaces: org.kde.KWin, org.kde.KWin.VirtualDesktopManager
│ ├── Consumed by: plasmashell, kcm modules
│ └── Depends on: org.freedesktop.login1 (system bus)
│
├── org.kde.plasmashell (plasmashell — self-registers)
│ ├── Object: /PlasmaShell
│ ├── Interfaces: org.kde.PlasmaShell, org.kde.osdService
│ └── Consumed by: KWin (OSD calls), KDE apps
│
├── org.kde.kglobalaccel (kglobalaccel daemon)
│ ├── Activated by: .service file
│ └── Consumed by: all KDE apps (global shortcuts)
│
├── org.kde.kded6 (KDE daemon)
│ ├── Activated by: .service file
│ └── Consumed by: KDE modules (status notifier, etc.)
│
├── [Phase DB-2] org.freedesktop.Notifications (redbear-notifications)
│ ├── Activated by: .service file
│ └── Consumed by: kf6-knotifications, all KDE apps
│
├── [Phase DB-5] org.freedesktop.StatusNotifierWatcher
│ └── Consumed by: system tray, plasma panel
│
└── [Phase DB-5] org.kde.JobViewServer
└── Consumed by: kf6-kjobwidgets, dolphin, file operations
9.3 KDE Framework D-Bus Consumer Map
| KF6 Module | D-Bus Usage | Current Build Flag | Re-enable Condition |
|---|---|---|---|
| kf6-kdbusaddons | Core D-Bus wrappers | ✅ Enabled | Already built |
| kf6-kservice | Service/plugin discovery | ✅ Enabled (via kdbusaddons) | Already built |
| kf6-kglobalaccel | Global shortcuts via D-Bus | ✅ Enabled | Needs kglobalaccel daemon running |
| kf6-knotifications | Desktop notifications | ✅ -DUSE_DBUS=ON |
Enabled against current notification scaffold; build-verified; supplementary QEMU runtime validation |
| kf6-solid | Hardware enumeration | ⚠️ -DUSE_DBUS=OFF |
Re-enable after UPower/udisks2 (DB-3) |
| kf6-kio | D-Bus service activation | ⚠️ -DUSE_DBUS=OFF |
Re-enable after core services proven (DB-3) |
| kf6-kwallet | Session D-Bus stable | ⚠️ Not in enabled subset | Real API-only build exists in-tree (DB-5) |
| kf6-kauth | Privileged actions | ✅ PolkitQt6-1 backend (v3.9) | Uses PolkitQt6-1 → redbear-polkit D-Bus daemon → real authorization |
| kf6-kidletime | Idle detection | ✅ Builds | Needs ScreenSaver D-Bus for full function |
| kf6-kjobwidgets | Job progress | ✅ Builds | Needs JobViewServer (DB-5) |
10. Security Model
10.1 Two-Layer Model
Layer 1: Redox Schemes (kernel-enforced capability security)
├── scheme:drm — only accessible to processes with explicit FD
├── scheme:pci — only accessible to driver-manager-launched drivers
├── scheme:input — only accessible to evdevd (which creates /dev/input/)
└── scheme:net — only accessible to network daemons
Layer 2: D-Bus Policy (daemon-enforced access control)
├── System bus: XML policy files in /etc/dbus-1/system.d/
├── Session bus: XML policy files in /etc/dbus-1/session.d/
└── Peer credentials: UID/GID verified via UNIX socket SCM_CREDENTIALS
Rule: Schemes are the real authority. D-Bus policy only gates who may ask a broker service to perform an operation. The broker service holds the scheme capability, not the client.
10.2 D-Bus Authentication
dbus-daemon uses the EXTERNAL SASL mechanism, which authenticates clients by their UNIX
socket credentials (UID/GID via SCM_CREDENTIALS). On Redox, this requires:
relibc'sSO_PASSCRED/SCM_CREDENTIALSsupport on Redox UNIX domain socketsgetpeereid()or equivalent — for the bus daemon to verify the connecting process's UID
Current repo status:
- relibc now exposes
SO_PASSCRED,SO_PEERCRED,SCM_CREDENTIALS, andgetpeereid()in the active tree - the bounded relibc test path now covers peer-credential lookup (
SO_PEERCRED) and credential delivery viarecvmsg()/SCM_CREDENTIALSon Redox UNIX domain sockets
That means the supplementary D-Bus risk is no longer raw absence of the credential path in relibc; it is broader desktop/runtime trust and integration with the real bus daemons.
10.3 Policy Granularity
Keep D-Bus XML policies coarse-grained:
- Who may own a bus name (e.g., only root may own
org.freedesktop.login1) - Who may send to a destination (e.g., any user may send to
org.freedesktop.login1.Manager) - Who may receive from a sender (e.g., any user may receive signals from login1)
Keep fine-grained authorization inside the Rust service:
redbear-sessiondchecks whether the requesting process's UID matches the active session ownerredbear-sessiondchecks whether the requesting process is the compositor before grantingTakeControl()redbear-polkitchecks at-console status before authorizing privileged actions
Do NOT try to map every scheme permission into D-Bus XML policy.
10.4 Session Bus Isolation
The session bus must only be accessible to the owning user:
DBUS_SESSION_BUS_ADDRESSshould point to a socket inXDG_RUNTIME_DIR(e.g.,/tmp/run/user/0/)- Socket permissions must be
0600(owner-only) - No TCP transport — UNIX sockets only (TCP is deprecated in D-Bus anyway)
11. Build Recipe Changes
11.1 New Recipes
| Recipe | Location | Template | Dependencies |
|---|---|---|---|
zbus |
local/recipes/libs/zbus/ |
custom (build-ordering marker) |
none |
redbear-sessiond |
local/recipes/system/redbear-sessiond/ |
cargo |
zbus, libredox, redox-syscall |
redbear-dbus-services |
local/recipes/system/redbear-dbus-services/ |
custom |
dbus (for staging dirs) |
redbear-notifications |
local/recipes/system/redbear-notifications/ |
cargo |
zbus |
redbear-upower |
local/recipes/system/redbear-upower/ |
cargo |
zbus |
redbear-udisks |
local/recipes/system/redbear-udisks/ |
cargo |
zbus |
redbear-polkit |
local/recipes/system/redbear-polkit/ |
cargo |
zbus |
Note:
redbear-nm(NetworkManager facade) is NOT in scope. Red Bear OS uses its nativeredbear-netctlfor network management. NM may be revisited if a future KDE Plasma NM applet integration is needed.
11.2 Modified Recipes
| Recipe | Change | Phase |
|---|---|---|
dbus |
Promote from WIP, add runtime validation | DB-5 |
kf6-knotifications |
Change -DUSE_DBUS=OFF → -DUSE_DBUS=ON |
DB-2 ✅ done |
kf6-solid |
Change -DUSE_DBUS=OFF → -DUSE_DBUS=ON, re-enable UPower backend |
DB-3 |
kf6-kio |
Change -DUSE_DBUS=OFF → -DUSE_DBUS=ON |
DB-5 |
kf6-kwallet |
Enable in config (recipe exists in-tree) | DB-5 |
qtbase (host) |
Consider enabling FEATURE_dbus=ON for host tools (qdbuscpp2xml/qdbusxml2cpp) | DB-2 |
11.3 Config Changes
redbear-full.toml additions:
[packages]
# D-Bus session/seat broker
redbear-sessiond = {}
redbear-dbus-services = {}
# [[files]] — redbear-sessiond init service
[[files]]
path = "/usr/lib/init.d/13_redbear-sessiond.service"
data = """
[unit]
description = "Red Bear session broker (login1)"
requires_weak = [
"12_dbus.service",
]
[service]
cmd = "redbear-sessiond"
type = "oneshot_async"
"""
KDE session launcher updates:
# After dbus-launch, set session variables
export XDG_SESSION_ID=c1 # redbear-sessiond session ID
export XDG_SEAT=seat0
export XDG_SESSION_TYPE=wayland
export XDG_RUNTIME_DIR=/tmp/run/user/0
export XDG_CURRENT_DESKTOP=KDE
# Ensure session bus environment is in D-Bus activation environment
dbus-update-activation-environment \
WAYLAND_DISPLAY \
XDG_SESSION_ID \
XDG_SEAT \
XDG_SESSION_TYPE \
XDG_RUNTIME_DIR \
XDG_CURRENT_DESKTOP \
KDE_FULL_SESSION \
DISPLAY
12. Testing and Validation
12.1 Phase DB-1 Tests
# System bus basic
dbus-send --system --dest=org.freedesktop.DBus --print-reply \
/org/freedesktop/DBus org.freedesktop.DBus.ListNames
# login1 presence
dbus-send --system --dest=org.freedesktop.login1 --print-reply \
/org/freedesktop/login1 org.freedesktop.login1.Manager.ListSessions
# login1 seat
dbus-send --system --dest=org.freedesktop.login1 --print-reply \
/org/freedesktop/login1/seat/seat0 org.freedesktop.DBus.Properties.GetAll \
string:"org.freedesktop.login1.Seat"
# Session bus basic
dbus-send --session --dest=org.freedesktop.DBus --print-reply \
/org/freedesktop/DBus org.freedesktop.DBus.ListNames
# KWin registration (after KWin starts)
dbus-send --session --dest=org.kde.KWin --print-reply \
/KWin org.kde.KWin.supportInformation
12.2 Phase DB-2 Tests
# kglobalaccel
dbus-send --session --dest=org.kde.kglobalaccel --print-reply \
/kglobalaccel org.freedesktop.DBus.Introspectable.Introspect
# kded6
dbus-send --session --dest=org.kde.kded6 --print-reply \
/kded org.freedesktop.DBus.Introspectable.Introspect
# Notifications
dbus-send --session --dest=org.freedesktop.Notifications --print-reply \
/org/freedesktop/Notifications org.freedesktop.Notifications.Notify \
string:"test" uint32:0 string:"" string:"Test" string:"Body" array:string:{} dict:string:string:{} int32:5000
# plasmashell
dbus-send --session --dest=org.kde.plasmashell --print-reply \
/PlasmaShell org.freedesktop.DBus.Introspectable.Introspect
12.3 QEMU Validation Script
Create local/scripts/test-dbus-qemu.sh:
#!/bin/sh
# Validates D-Bus stack in QEMU-booted Red Bear OS
# Usage: ./local/scripts/test-dbus-qemu.sh --check
echo "=== D-Bus System Bus ==="
echo "System bus socket:"
ls -la /run/dbus/system_bus_socket 2>&1
echo "Bus names:"
dbus-send --system --dest=org.freedesktop.DBus --print-reply \
/org/freedesktop/DBus org.freedesktop.DBus.ListNames 2>&1
echo "login1 sessions:"
dbus-send --system --dest=org.freedesktop.login1 --print-reply \
/org/freedesktop/login1 org.freedesktop.login1.Manager.ListSessions 2>&1
echo ""
echo "=== D-Bus Session Bus ==="
echo "Session bus address:"
echo "$DBUS_SESSION_BUS_ADDRESS"
echo "Session bus names:"
dbus-send --session --dest=org.freedesktop.DBus --print-reply \
/org/freedesktop/DBus org.freedesktop.DBus.ListNames 2>&1
13. Risks and Mitigations
13.1 Technical Risks
| Risk | Impact | Likelihood | Mitigation |
|---|---|---|---|
| UNIX socket credential passing regresses on Redox | D-Bus authentication fails | Medium | Keep the relibc UDS credential tests in the preserved proof path; if broken again, fall back to cookie auth or patch relibc |
| KWin login1 expectations exceed our minimal subset | KWin crashes or refuses to start | Medium | Start with KWin's Noop fallback; add methods incrementally as KWin logs errors |
| zbus async runtime conflicts with Redox event system | zbus doesn't build or run | Low | zbus supports multiple async runtimes; test tokio + Redox early |
| D-Bus service activation files not picked up by dbus-daemon | Services must be started manually | Low | dbus-daemon 1.16.2 supports classic activation; verify search path in redox.patch |
| Device major/minor mapping unstable | TakeDevice returns wrong device | Medium | Use udev-shim as single source of truth; add validation tests |
| PAM not available for elogind-like session tracking | Cannot use elogind directly | Certain | That's why we're building redbear-sessiond — no PAM dependency |
| Peer credential path behaves differently under real dbus-daemon load | System bus policy can't verify UIDs reliably | Medium | The relibc credential path is now present and bounded-tested; next tighten with real dbus-daemon/session-bus runtime validation |
13.2 Integration Risks
| Risk | Impact | Mitigation |
|---|---|---|
| KDE Plasma 6 accumulates more systemd assumptions | More D-Bus services needed than anticipated | Monitor KDE Plasma releases; test each upgrade |
| Re-enabling D-Bus in kf6 components exposes build failures | Build breakage in previously-stable recipes | Re-enable one component at a time, with CI gating |
| Init service ordering conflicts | redbear-sessiond starts before dbus-daemon | Use requires_weak = ["12_dbus.service"] in init config |
13.3 Escalation Triggers
-
If
TakeDevice()cannot be made to work via major/minor → scheme path mapping: Add a small Redox-only KWin session backend that talks to the native seat/device broker directly (bypasses D-Bus for device access). Keep the rest of the D-Bus architecture unchanged. -
If zbus cannot build on Redox (async runtime incompatibility): Fall back to
libdbus-1C bindings for Rust services (via thedbuscrate). Less ergonomic but proven to work with the existing dbus build. -
If KDE hard-requires more freedesktop services than expected: Add them as individual compatibility daemons, not a generic bridge. Each daemon wraps exactly one freedesktop contract.
14. Qt 6.11 D-Bus Coverage
This appendix closes an important scoping gap in the plan. Qt 6.11 itself already carries D-Bus coverage for the Redox target, and the KDE build stack already has a working code generation path for D-Bus XML tooling during cross-compilation. The missing pieces are higher-level freedesktop service contracts and the staged re-enablement of KF6 components that were intentionally built with D-Bus disabled.
14.1 Qt Build Configuration
The current Qt 6.11 setup splits D-Bus support differently between target and host builds.
Target build (qtbase for Redox):
-DFEATURE_dbus=ON(line 419 of recipe.toml)"dbus"listed as build dependency (line 16)- Qt6DBus module built and staged
- libQt6DBus.so.6.11.0 staged to sysroot
Host build (qtbase-host):
-DFEATURE_dbus=OFF(line 104)- Profile name:
qtbase-host-6.11.0-gui-xml-wayland-no-qdbus-host(line 63) - qdbuscpp2xml and qdbusxml2cpp subdirectories disabled via Python patching (lines 71-74)
- These tools are needed at BUILD time by kf6-kdbusaddons, kwin, kf6-kio for D-Bus XML → C++ code generation
The practical result is that QtDBus support exists in the target sysroot today. Build-time D-Bus tooling for host-side code generation is the only area still running through a workaround path.
14.2 qdbuscpp2xml/qdbusxml2cpp Provisioning
The current provisioning strategy is intentionally pragmatic.
Since the host build disables D-Bus, KDE recipes provision these tools via symlinks:
- kf6-kdbusaddons (lines 22-32): First tries
${HOST_BUILD}/libexec/$tool, then falls back to/usr/bin/qdbuscpp2xmland/usr/bin/qdbusxml2cppfrom the host system - kwin (line 67):
for tool in moc rcc uic qdbuscpp2xml qdbusxml2cpp wayland-scanner; do - kf6-kio (line 33): Same pattern as kwin
The host system packages provide these tools during cross-compilation. This is a pragmatic workaround, not a long-term solution. Future improvement: enable FEATURE_dbus=ON in the host build once D-Bus session bus validation passes on the host toolchain.
14.3 KF6 Components with D-Bus Disabled
Updated 2026-07-26 (v3.1). 20 of the 24 KF6 components below now build with
-DUSE_DBUS=ON. The remaining 4 are limited by daemon-binary or Qt-binding
prerequisites, not by the USE_DBUS flag itself. Re-enable each only when the
listed service contract is actually available at runtime.
| Recipe | Flag | D-Bus Service Prerequisite | Phase to Re-enable |
|---|---|---|---|
| kf6-kconfig | ✅ -DUSE_DBUS=ON |
Config file watching via D-Bus | DB-5 |
| kf6-kcoreaddons | ✅ -DUSE_DBUS=ON |
File type detection via D-Bus | DB-5 |
| kf6-kio | ✅ -DUSE_DBUS=ON |
D-Bus service activation, org.kde.KIO::* | DB-5 |
| kf6-knotifications | ✅ -DUSE_DBUS=ON |
org.freedesktop.Notifications | DB-2 (runtime validation build-verified; QEMU validation supplementary) |
| kf6-solid | ✅ -DUSE_DBUS=ON |
org.freedesktop.UPower + org.freedesktop.UDisks2 + org.freedesktop.login1 | DB-3 |
| kf6-kcmutils | ✅ -DUSE_DBUS=ON |
KCM QML data via D-Bus | DB-5 |
| kf6-kconfigwidgets | ✅ -DUSE_DBUS=ON |
Config dialog D-Bus sync | DB-5 |
| kf6-kguiaddons | ✅ -DUSE_DBUS=ON |
Color scheme via XDG portals | DB-5 |
| kf6-kpackage | (no flag — defaults ON) | Package metadata via D-Bus | DB-5 |
| kf6-kiconthemes | ✅ -DUSE_DBUS=ON |
Icon theme via D-Bus | DB-5 |
| kf6-kitemviews | ✅ -DUSE_DBUS=ON |
KIO integration via D-Bus | DB-5 |
| kf6-kitemmodels | ✅ -DUSE_DBUS=ON |
KIO integration via D-Bus | DB-5 |
| kf6-kjobwidgets | ✅ -DUSE_DBUS=ON |
Job progress via org.kde.JobViewServer | DB-5 |
| kf6-kwallet | (no flag — BUILD_KWALLETD=OFF) |
org.freedesktop.Secrets; depends on kwalletd binary |
DB-5 (after kwalletd build) |
| kf6-kauth | ✅ uses PolkitQt6-1 backend (v3.9) | polkit-1 backend linked against PolkitQt6-1 → redbear-polkit D-Bus daemon |
DB-3 (now enabled) |
| kf6-kded6 | ✅ kded6 daemon built (v4.0) | kded6 binary wrapped with offscreen QPA wrapper; org.kde.kded6 activation |
DB-5 (enabled) |
| kf6-kglobalaccel | ✅ kglobalacceld5 daemon built (v4.0) | kglobalacceld5 binary wrapped with offscreen QPA wrapper; org.kde.KGlobalAccel activation |
DB-5 (enabled) |
| kirigami | (no flag — defaults ON) | Cross-device sharing | DB-5 |
| plasma-framework | (no flag — defaults ON) | Plasma widget D-Bus integration | DB-5 |
Action items (deferred to specific rounds):
- kf6-kwallet — Enable
BUILD_KWALLETD=ON. Requires constructing thekwalletdbinary in the current recipe (or splitting it into a separate daemon recipe). The user-space runtime depends on theorg.freedesktop.Secretsservice contract — already provided byredbear-notificationsplumbing but not wired in production mode yet. - kf6-kauth — ✅ DONE (v3.9). The polkit-qt6-1 recipe now packages
the upstream PolkitQt6-1 0.200.0 tarball, and kf6-kauth's recipe now
uses
-DKAUTH_BACKEND_NAME=POLKITQT6-1 -DKAUTH_HELPER_BACKEND_NAME=POLKITQT6-1to link thepolkit-1backend against PolkitQt6-1, which talks to theredbear-polkitD-Bus daemon for real authorization. - kf6-kded6 / kf6-kglobalaccel — Build the daemon binaries. The recipes currently ship the
client libraries only. The corresponding D-Bus service activation files are intentionally
removed from
redbear-dbus-services/files/session-services/(honest-absence pattern).
14.4 Re-enablement Priority Order
Re-enablement must follow service availability, not package build order.
- DB-1 (now): redbear-sessiond provides org.freedesktop.login1 → kf6-solid UPower backend can connect (but needs UPower daemon too)
- DB-2 (now): redbear-notifications provides org.freedesktop.Notifications → kf6-knotifications enabled (was DB-2 priority)
- DB-3 (now): redbear-upower provides org.freedesktop.UPower → kf6-solid enabled (was DB-3 priority)
- DB-4 (now): redbear-udisks provides org.freedesktop.UDisks2 → kf6-solid UDisks2 backend
- DB-5 (pending kwalletd): Full desktop services → kf6-kwallet (after
kwalletd)
The key insight: QtDBus is NOT the gap. Qt6DBus builds and kf6-kdbusaddons provides the convenience layer. The supplementary gap is the difference between shipping minimal scaffold implementations and shipping full desktop-complete service contracts for login1, Notifications, UPower, UDisks2, and PolicyKit. NetworkManager remains deferred and is not part of the current Red Bear OS implementation scope.
Phase 3/4 D-Bus Improvement Plan (2026-04-25 Assessment)
Assessment scope: All Red Bear D-Bus service implementations (redbear-sessiond, redbear-notifications, redbear-upower, redbear-udisks, redbear-polkit), plus the dbus-daemon itself, conducted via 4 parallel evaluation agents (Oracle + 2 explore + librarian).
Key finding: Phase 2 (kwin_wayland --virtual) should work without D-Bus changes. KWin falls back to NoopSession when logind is unavailable, and the Noop backend bypasses login1 entirely.
Key finding: Phase 3 has one hard gate: TakeDevice FD passing. This cannot be bypassed.
Assessment Summary
Fragility ratings across services:
| Service | Rating | Primary concern |
|---|---|---|
redbear-sessiond |
5/5 | login1 is the critical path for DRM compositor |
redbear-polkit |
✅ v0.2 | Real authorization (subject UID extraction, @group / * / !uid policy syntax, default-deny); 13 unit tests |
dbus-daemon |
2/5 | 24-line patch is stable but not validated under real session bus load |
redbear-notifications |
2-3/5 | ✅ v0.3 — ActionInvoked signal emission via InvokeAction method; backend reports version 0.3 |
redbear-upower |
2-3/5 | ✅ v0.2 — Changed signal emission; new properties: TimeToFull, TimeToEmpty, Energy, EnergyRate, BatteryLevel, PowerSupply, Serial; 7 unit tests. QEMU validation still pending. |
redbear-udisks |
2-3/5 | ✅ v0.2 — Mount / Unmount methods (fork+exec of ext4d / fatd); MountPoints / IdType properties; 9 unit tests |
Phase 2 assessment: D-Bus is NOT on the critical path for kwin_wayland --virtual. The NoopSession backend in KWin bypasses logind entirely, which means Phase 2 compositor bring-up should succeed without D-Bus changes.
Phase 3 hard gate: TakeDevice FD passing + PauseDevice/ResumeDevice signal emission. This is required for KWin to own real DRM and input devices through the freedesktop session protocol. No bypass exists.
Phase 4 broader surface: kglobalaccel binary, kded6 binary, StatusNotifierWatcher, Inhibit methods, session identity derivation.
Phase 3 Gate (DRM Compositor) — Required D-Bus Changes
Four fixes are required before KWin can use real hardware devices through login1:
| # | Fix | Current state | Required change | Status (2026-07-26) |
|---|---|---|---|---|
| 1 | Manager.Inhibit + CanPowerOff/CanSuspend/CanHibernate stubs |
Implemented | Return "na" string from each method; required by KDE's session management layer |
✅ done (v3.0) |
| 2 | PauseDevice/ResumeDevice signal emission |
Implemented | Emit uus (major, minor, type) for PauseDevice and uuh (major, minor, fd) for ResumeDevice in session.rs when device state changes |
✅ done (v3.1) — take_device and release_device now emit signals; runtime validation via QEMU pending |
| 3 | Dynamic device enumeration | Implemented | Query udev-shim at runtime for major/minor -> scheme path mapping; remove hardcoded lookup table | ✅ done (v3.1) — device_map.rs rewritten with no hardcoded entries, lazy filesystem scan + cache + refresh |
| 4 | Session methods | SetIdleHint, SetLockedHint, SetType, Terminate return errors; runtime validation requires QEMU |
Structurally implemented; runtime validation requires QEMU |
Phase 4 Gate (KDE Plasma Session) — Required D-Bus Changes
| # | Improvement | Current state | Required change |
|---|---|---|---|
| 1 | `StatusNotifierWatcher: activation file staged | Register org.freedesktop.StatusNotifierWatcher on session bus; track registered items, emit ItemRegistered/ItemUnregistered signals |
|
| 2 | kglobalaccel binary build |
KDE app recipe builds library, daemon binary is a separate recipe step | Add kglobalaccel binary to local/recipes/kde/kf6-kglobalaccel/ or create separate recipe |
| 3 | kded6 binary build |
KDE app recipe builds library, daemon binary is a separate recipe step | Add kded6 binary to local/recipes/kde/kf6-kded6/ or create separate recipe |
| 4 | Session identity derivation | Hardcoded to c1, root, uid=0 |
Query real session environment variables (XDG_SESSION_ID, XDG_SEAT) and derive identity from the actual login session |
| 5 | UPower Changed signal emission + polling |
No signals, no polling | Emit Changed signal when power state changes; implement property polling for OnBattery, Percentage, TimeToEmpty |
| 6 | Notifications ActionInvoked signal + capabilities |
Activation file staged; runtime deferred | Emit ActionInvoked(uint32, string) when user clicks notification action; expand GetCapabilities to include body, actions, icon-static |
| 7 | Stoppable daemons | Services use supplementary() with no shutdown channel |
Replace supplementary() in all services with proper shutdown signal channels; enable service restart and clean shutdown |
KWin Method-by-Method Readiness Matrix
| KWin D-Bus call | Current impl | Phase 2 needed | Phase 3 needed | Status (2026-07-26) |
|---|---|---|---|---|
GetSession("auto") |
via NoopSession | No (bypasses logind) | Yes | ✅ implemented |
TakeControl(false) |
Via login1 | No | Yes | ✅ implemented |
TakeDevice(226, 0) (DRM) |
Via dynamic DeviceMap | No | Yes (critical) | ✅ structurally implemented; QEMU runtime pending |
TakeDevice(13, 64+) (input) |
Via dynamic DeviceMap | No | Yes (critical) | ✅ structurally implemented; QEMU runtime pending |
PauseDevice signal |
Emitted on take_device |
No | Yes (critical) | ✅ done (v3.1) |
ResumeDevice signal |
Emitted on release_device with fresh FD |
No | Yes (critical) | ✅ done (v3.1) |
Seat.SwitchTo |
Via login1 | No | Yes | ✅ implemented |
Manager.Inhibit |
Implemented | No | Yes | ✅ implemented |
CanPowerOff/CanSuspend/CanHibernate |
Implemented | No | Yes | ✅ implemented |
PrepareForShutdown |
Via ACPI kstop verb | No | Yes | ✅ implemented |
PrepareForSleep |
Emitted via ACPI CheckSleep verb, paired with resume |
No | Yes | ✅ done (v3.1) |
Completeness by Service
| Service | Methods real | Total expected | Completeness |
|---|---|---|---|
login1.Manager |
3 | ~30+ | ~10% |
login1.Session |
7 | ~15+ | ~47% |
login1.Seat |
1 | 5 | ~20% |
Notifications |
4 | ~5 | ~80% |
UPower |
3 | ~5 | ~60% |
UDisks2 |
4 | ~8+ | ~50% |
PolicyKit1 |
3 | ~6+ | ~50% |
Implemented KDE D-Bus Services
| Service | Used by | Status | Impact |
|---|---|---|---|
org.kde.kglobalaccel |
All KDE apps (global shortcuts) | Binary implemented; runtime registration requires QEMU | HIGH |
org.kde.kded6 |
KDE daemon (status notifier, etc.) | Binary implemented; runtime registration requires QEMU | HIGH |
| `org.freedesktop.StatusNotifierWatcher: activation file staged | MEDIUM | ||
| `org.kde.ksmserver: activation file staged | MEDIUM | ||
org.freedesktop.ScreenSaver |
Screen locking | Activation file staged; runtime deferred | MEDIUM |
Implementation Priority Order
redbear-sessiondPhase 3 methods (enables DRM compositor session) — done (v3.1) forPauseDevice/ResumeDevice/PrepareForSleepemission- Dynamic device enumeration (enables non-static hardware discovery) — done (v3.1) via
device_map.rsrewrite - Stoppable daemons (enables testing and restart)
StatusNotifierWatcher(enables system tray)UPowerpolling + signals (enables battery applet)- Session identity improvements (enables non-root sessions)
15. Review Findings (2026-07-27)
This section records verified evidence from a read-only review of the D-Bus integration surface. Every finding cites an exact path and distinguishes build-wired (the code or config exists and the build system knows about it) from runtime-proven (the behavior has been validated in a QEMU or bare-metal boot). No source code, recipe, or config was modified during this review. Where a contradiction between the existing text above and the source tree was found, the resolution is noted; where evidence is inconclusive, the uncertainty is labeled.
F1. dbus 1.16.2 is recipe-and-patch based (confirmed)
Path: local/recipes/system/dbus/recipe.toml
The dbus package uses a tarball source (dbus-1.16.2.tar.xz, BLAKE3 pinned) with two
patches: redox.patch and dbus-root-uid.patch. The meson template disables systemd,
launchd, X11 autolaunch, and forces the system bus socket to
/run/dbus/system_bus_socket via -Dsystem_socket. The build dependency is expat only.
This is not a local fork. It is the upstream freedesktop tarball plus two overlay patches,
built with the meson template. The recipe carries a #TODO: validate runtime marker that
remains open.
F2. zbus is a downstream Cargo dependency with a marker recipe (confirmed)
Path: local/recipes/libs/zbus/recipe.toml
The zbus recipe (version = "0.1.0") is a custom-template no-op. Its build script is:
echo "zbus: build-ordering marker — actual crate fetched by downstream Cargo builds"
The marker source at local/recipes/libs/zbus/source/Cargo.toml declares version = "5.18.0"
but is never compiled by the cookbook. The actual zbus crate that links into redbear-sessiond,
redbear-notifications, redbear-upower, redbear-udisks, redbear-polkit, and
redbear-statusnotifierwatcher is resolved by Cargo from each daemon's own Cargo.toml
dependency declaration (e.g. zbus = { version = "5", ... }).
This means the zbus version actually linked depends on each daemon's Cargo.lock resolution,
not on the marker recipe. The marker exists solely for build-ordering in the cookbook
dependency graph.
F3. Recipe.toml vs Cargo.toml version drift (all Red Bear D-Bus daemons)
Every Red Bear D-Bus daemon recipe has a recipe.toml version of 0.1.0 while its source
Cargo.toml carries the current Red Bear OS branch version 0.3.1:
| Recipe | recipe.toml version |
source/Cargo.toml version |
|---|---|---|
redbear-sessiond |
0.1.0 |
0.3.1 |
redbear-notifications |
0.1.0 |
0.3.1 |
redbear-upower |
0.1.0 |
0.3.1 |
redbear-udisks |
0.1.0 |
0.3.1 |
redbear-polkit |
0.1.0 |
0.3.1 |
redbear-statusnotifierwatcher |
0.1.0 |
0.3.1 |
redbear-wifictl |
0.1.0 |
0.3.1 |
This drift is a known pattern for cargo-template recipes: the cookbook builds the crate
using Cargo.toml, so the recipe.toml version field is a placeholder that is not consumed
at build time. The drift is documented here for accuracy. The source Cargo.toml version
(0.3.1) is the authoritative version for each daemon. The status text elsewhere in this
document that references daemon versions (e.g. "v0.2", "v0.3") refers to implementation
milestones tracked in commit history and Cargo.toml, not to the recipe.toml placeholder.
F4. redbear-wifictl D-Bus interface is a confirmed no-op stub
Path: local/recipes/system/redbear-wifictl/source/src/dbus_nm.rs
The file defines types (NmWifiDevice, NmDeviceState, NmAccessPoint) and a
register_nm_interface() function, but the function body is a no-op:
pub fn register_nm_interface() {
#[cfg(feature = "dbus-nm")]
{
let _ = std::any::type_name::<zbus::Address>();
}
log::info!("wifictl: D-Bus NetworkManager interface registered");
}
The dbus-nm feature is not in the default feature set (default = [] in Cargo.toml),
so the #[cfg] block is compiled out in default builds. Even when the feature is enabled,
the body evaluates std::any::type_name::<zbus::Address>() — a compile-time type-name
reference that performs no runtime D-Bus registration. The log::info! message prints
unconditionally, creating the false impression that registration occurred.
No D-Bus object path, bus name, or interface is registered at any point. This is a
placeholder stub, not a working NetworkManager facade. The redbear-wifictl package IS
wired in config/redbear-mini.toml (package entry + init service at
/etc/init.d/11_wifictl.service), so the binary ships in the redbear-mini image, but its
D-Bus surface is inert.
This is consistent with the plan's deferral of org.freedesktop.NetworkManager (Red Bear OS
uses redbear-netctl), but the stub's existence in the source tree should be explicitly
documented rather than implied.
F5. redbear-statusnotifierwatcher is not wired into any config and lacks build-dependency declarations
Two distinct gaps confirmed:
Gap A — config wiring: redbear-statusnotifierwatcher does not appear in any
config/redbear-*.toml file (grep -rn "statusnotifier" config/redbear-*.toml returns zero
matches). The binary will not be present in any live ISO. Despite this, the activation file
local/recipes/system/redbear-dbus-services/files/session-services/org.freedesktop.StatusNotifierWatcher.service
is staged and ships in the image, pointing to Exec=/usr/bin/redbear-statusnotifierwatcher.
D-Bus activation will fail at runtime because the binary does not exist in the image. The
inline annotation in section 4.3 above has been updated to reflect this.
Gap B — recipe build dependencies: The recipe at
local/recipes/system/redbear-statusnotifierwatcher/recipe.toml uses template = "cargo"
with no [build] dependencies section. The source Cargo.toml depends on zbus and
tokio, but the recipe does not declare zbus or dbus as build-ordering dependencies to
the cookbook. This means the cookbook has no guaranteed build-ordering constraint ensuring
zbus is available before this recipe compiles. In practice, Cargo resolves zbus directly
from crates.io (or the [patch.crates-io] overlay), so compilation succeeds, but the
cookbook dependency graph does not encode the relationship.
The daemon's 12 unit tests pass on the host (cargo test without --target), which is the
sanctioned test path for pure-logic crates per the canonical build policy. No target-arch or
QEMU runtime validation has been performed.
F6. Session bus and D-Bus activation are not end-to-end tested
System bus: Build-wired and config-wired. config/redbear-full.toml stages
/etc/init.d/12_dbus.service which launches
dbus-daemon --system --nopidfile --address=unix:path=/run/dbus/system_bus_socket.
The dbus-send and dbus-launch tools are built by the dbus recipe
(tools/meson.build lines 71 and 43 respectively). However, no QEMU or bare-metal runtime
validation has confirmed that the system bus socket appears, that dbus-send --system ListNames returns a non-empty list, or that org.freedesktop.login1 registers successfully.
The validation commands in section 12.1 above are aspirational, not yet executed.
Session bus: Build-wired via a shell script. The file
local/recipes/system/redbear-greeter/source/redbear-session-launch (line 127) conditionally
runs eval "$(dbus-launch --sh-syntax)" and exports DBUS_SESSION_BUS_ADDRESS. This is
scripted, not init-managed, and has never been runtime-validated. No test confirms that the
session bus starts, that DBUS_SESSION_BUS_ADDRESS is set in the KDE process environment,
or that session-bus D-Bus activation (.service file autostart) works end-to-end.
Activation: D-Bus service activation files are staged in
/usr/share/dbus-1/{system,session}-services/ by the redbear-dbus-services recipe, but
activation has never been runtime-tested. The test-dbus-qemu.sh script described in
section 12.3 is a specification in this document, not a committed script in
local/scripts/.
Current verification limit: All D-Bus claims in this document beyond "builds" and
"host unit tests pass" require a QEMU boot of a redbear-full (or equivalent) image with
the desktop session path active. This has not been done. The plan's exit criteria in phases
DB-1 and DB-2 correctly note "runtime validation requires QEMU" for each item.
F7. Redox fork foundation commits already present (confirmed)
Three commits relevant to D-Bus runtime on Redox are present in the local fork branches:
| Fork | Commit | Subject | Path |
|---|---|---|---|
| kernel | 40e3c491 |
event: implement kdup so epoll fds can be duplicated (fixes tokio on Redox) |
local/sources/kernel/ |
| relibc | 733da068 |
fix(redox): translate POSIX F_DUPFD_CLOEXEC (1030) to Redox syscall ABI (5) |
local/sources/relibc/ |
| relibc | dd2cd443 |
relibc: epoll_pwait must not panic on EVENT_TIMEOUT_ID |
local/sources/relibc/ |
These commits are foundational for zbus and tokio on Redox: kdup allows epoll-based event
loops to duplicate file descriptors (required by tokio's I/O driver), F_DUPFD_CLOEXEC
translation ensures fcntl compatibility, and the epoll_pwait fix prevents a panic on
timeout events that tokio generates routinely. Without these, zbus (which uses tokio for its
async runtime) would not function at runtime. Their presence is necessary but not sufficient
for D-Bus runtime validation — the session-bus and activation gaps (F6) remain open.
F8. Summary: build-wired vs runtime-proven
| Claim in this document | Build-wired? | Runtime-proven? | Evidence |
|---|---|---|---|
| dbus-daemon 1.16.2 builds | Yes | No (QEMU pending) | recipe.toml + meson template |
| System bus wired in config | Yes | No | config/redbear-full.toml 12_dbus.service |
| Session bus scripted | Yes (shell script) | No | redbear-session-launch line 127 |
| redbear-sessiond registers login1 | Yes (source builds, host tests pass) | No | 32 unit tests host-only; QEMU pending |
| D-Bus activation files staged | Yes | No | redbear-dbus-services/files/ |
| StatusNotifierWatcher in image | No (not in config) | No | F5 above |
| redbear-wifictl NM D-Bus | No (no-op stub) | No | F4 above |
| zbus marker recipe | Yes (no-op) | N/A (Cargo resolves real crate) | F2 above |
| dbus-send / dbus-launch built | Yes | No (not runtime-tested) | tools/meson.build |
| Kernel/relibc epoll fixes | Yes (in fork history) | No (not exercised under real bus load) | F7 above |
16. Round 2 Findings (2026-07-27)
This section records verified evidence from a second read-only review of the D-Bus integration surface, conducted as the doc-cleanup phase of the second implementation round (the 5-lane review). It follows the same evidence discipline as §15: every finding cites an exact path, distinguishes working-tree present (the code exists in the current source tree, including uncommitted round-2 changes) from runtime-proven (validated in QEMU or bare metal), and labels uncertainty where evidence is inconclusive.
Cross-reference: §15 (2026-07-27 round-1 review) established the build-wired vs runtime-proven baseline. This section documents the round-2 delta against that baseline.
G1. StatusNotifierWatcher — sender validation, owner-keyed registry, and lifecycle purging (APPLIED)
Path: local/recipes/system/redbear-statusnotifierwatcher/source/src/main.rs
The StatusNotifierWatcher was substantially rewritten in round 2. The changes verified in the working tree:
-
Sender-validated registration.
register_status_notifier_item,register_status_notifier_host,unregister_status_notifier_item, andunregister_status_notifier_hostnow accept#[zbus(header)] hdr: Header<'_>and extract the caller's unique bus name viahdr.sender(). Registrations are stored in an owner-keyedRegistry(HashMap<String, HashSet<String>>) rather than a flatHashSet. Only the owning caller may unregister its own entries — a wrong-owner unregister returnsfalsewithout side effect. -
Input validation.
validate_input()rejects empty strings, strings longer thanMAX_INPUT_LEN(256), and strings containing NUL or other control characters (char::is_control()). Applied to both item and host registration parameters. -
NameOwnerChanged purging. A background
tokio::spawntask subscribes toorg.freedesktop.DBus.NameOwnerChangedvia a#[proxy]trait. When a bus name vanishes (new_ownerempty,old_ownernon-empty),watcher.purge_owner(&old_owner)removes all items and hosts owned by that name. This prevents stale entries from disconnected clients. -
Bounded entries.
MAX_ENTRIES = 1024with FIFO eviction (evict_oldest()drops the front ofinsertion_order). Prevents unbounded growth from a misbehaving or hostile client. -
Test coverage. 22 unit tests (up from 12): ownership enforcement (wrong owner cannot unregister), purge on owner loss, input validation (empty, oversized, control chars), and bounded eviction (oldest evicted at capacity, empty-owner cleanup). All tests pass on the host.
Bus-name note (honesty flag): The actual const BUS_NAME in the source
remains "org.freedesktop.StatusNotifierWatcher" (line 14, unchanged). The
recipe.toml header comment was updated from org.freedesktop to
org.kde.StatusNotifierWatcher, and the #[interface(name = ...)] annotation
remains "org.freedesktop.StatusNotifierWatcher". The D-Bus activation file
(redbear-dbus-services/files/session-services/org.freedesktop.StatusNotifierWatcher.service)
and the Name= line inside it also use the org.freedesktop form. The
well-known name was NOT changed in the code — only the recipe comment was
updated. If the intended fix was to switch to org.kde.StatusNotifierWatcher
(the name Plasma's own statusnotifierwatcher.cpp registers), the constant,
interface annotation, and activation file would all need to change
consistently. As of the working tree at HEAD, they do not.
G2. redbear-notifications — sender-validated InvokeAction (APPLIED)
Path: local/recipes/system/redbear-notifications/source/src/main.rs
-
Notification ownership record. A
NotificationRecord { owner: String, action_keys: Vec<String> }is stored in aMutex<HashMap<u32, NotificationRecord>>on everyNotify()call. The caller's unique bus name (hdr.sender()) is captured as the owner, and declared action keys (even indices of theactionsarray per the freedesktop spec) are extracted. -
InvokeAction sender validation.
InvokeActionnow takes#[zbus(header)] hdr: Header<'_>and returnsfdo::Result<()>instead of(). Thevalidate_invoke(id, caller, action_key)helper checks three conditions: (a) the notification ID is known, (b) the caller's unique bus name matches the stored owner, and (c) the action key was declared in the originalNotifycall. A spoofedInvokeActionfrom a different client is rejected withfdo::Error::Failed. -
Lifecycle cleanup.
CloseNotificationcallsremove_notification(id)so the ownership record is cleaned up. -
Test coverage. New tests verify: correct owner + declared key →
Ok, wrong owner → error ("not notification owner"), unknown ID → error, and post-removal invocation → error ("unknown notification id").
G3. redbear-wifictl — NM root State enum 0..70 and OwnedObjectPath types (APPLIED)
Path: local/recipes/system/redbear-wifictl/source/src/dbus_nm.rs
-
NmState enum (0..70). A new
NmStateenum (Unknown=0, Asleep=10, Disconnected=20, Disconnecting=30, Connecting=40, ConnectedLocal=50, ConnectedSite=60, ConnectedGlobal=70) was added. This is distinct fromNmDeviceState(0..120). The rootorg.freedesktop.NetworkManager.Stateproperty now returnsNmState::from_device_state(...).as_u32()instead of the raw per-device state. This closes a class-math bug where aNmDeviceStatevalue (e.g.Activated=100) could leak onto the rootStateproperty, exceeding the 0..70NMStatecontract that Qt'sQNetworkConfigurationManagerexpects. -
OwnedObjectPath return types.
get_devices(),get_all_devices(),active_connections(),access_point_paths(),active_access_point(), anddevice_path()all changed from returningString/Vec<String>toOwnedObjectPath/Vec<OwnedObjectPath>/fdo::Result<OwnedObjectPath>. Atry_path()helper converts path strings toOwnedObjectPathwithfdo::Errormapping instead of.expect(). This matches the typed-path convention already used byredbear-sessiond,redbear-udisks, andredbear-upower. -
Test coverage. New tests verify:
NmStatedefault isUnknown(0),as_u32()matches the NetworkManager spec for all 8 variants,from_device_statemapsActivated → ConnectedGlobal, connecting states →Connecting, and disconnected states →Disconnected. A dedicated test asserts thatNmStatenever exceeds 70 for anyNmDeviceStateinput.
G4. redbear-sessiond — test environment guard (APPLIED)
Path: local/recipes/system/redbear-sessiond/source/src/manager.rs (test module)
The can_methods_return_na test previously hard-coded assert_eq!(... "yes") for can_power_off/can_reboot/can_suspend. On a Linux host
(where cargo test runs for host-runnable unit tests), the kstop_writable()
probe returns false (no /scheme/sys/kstop), so the Can* methods
correctly return "na" — causing the test to fail. The fix mirrors the
runtime detection:
let expected = if kstop_writable() { "yes" } else { "na" };
assert_eq!(manager.can_power_off().unwrap(), expected);
This allows the test to pass on both Redox (where kstop is writable → "yes") and Linux host (where kstop is absent → "na"). No production code changed; only the test assertion adapts.
G5. Honest capabilities — pre-existing (CONFIRMED)
Path: local/recipes/system/redbear-notifications/source/src/main.rs
GetCapabilities() returns vec!["body".to_owned(), "body-markup".to_owned()]
— an honest minimal set. A unit test explicitly asserts that "actions" and
"persistence" are NOT advertised until the corresponding features are
implemented. This was already present at HEAD (round-1 or earlier); round 2
did not change it.
G6. verify-fork-functions exclusion — pre-existing, narrowly scoped (CONFIRMED)
Path: local/scripts/verify-fork-functions.sh + .verify-fork-functions.exclude files
The script only covers local/sources/*/ forks with upstream remotes. D-Bus
daemons live in local/recipes/system/redbear-*/source/ and are not in
scope for fork-function verification (they have no upstream). Three exclude
files exist (base, kernel, installer), each listing specific
file:function_name pairs with justifying comments. Zero blanket or D-Bus-
related exclusions. This was already present at HEAD; round 2 did not change it.
G7. write_all error propagation — pre-existing, partial (CONFIRMED)
Path: local/recipes/system/redbear-sessiond/source/src/manager.rs
redbear-sessiond's power-off/suspend/reboot paths use
if let Err(e) = f.write_all(b"shutdown") with error recovery (resets
preparing_for_shutdown flag, returns fdo::Error::Failed). This was already
present at HEAD. Other daemons (redbear-authd, redbear-udisks test code,
cpufreqd) still swallow write_all errors with let _ =, .unwrap(), or
.is_ok(). Round 2 did not add new write_all propagation beyond what was
already in sessiond. The gap remains open for authd/udisks/cpufreqd.
G8. Inhibitor lifecycle reaping — NOT applied (GAP REMAINS)
Path: local/recipes/system/redbear-sessiond/source/src/manager.rs
The inhibit() method registers inhibitors: it creates a UnixStream::pair(),
stores the caller FD in inhibitor_fds, pushes an InhibitorEntry into
runtime.inhibitors, and returns the other end as OwnedFd. However, no
reaping logic exists: the inhibitor_fds and runtime.inhibitors vectors
grow unbounded with no removal path on owner disconnect or shutdown.
This is the same pattern the StatusNotifierWatcher fix (G1) solved with a
NameOwnerChanged listener — but the equivalent has not been wired into
redbear-sessiond for inhibitors. Round 2 did not modify manager.rs
inhibitor code (only the test module changed, per G4). This remains a gap.
G9. Round 2 summary: applied vs not-applied
| Item | Claimed as | Verified state | Evidence |
|---|---|---|---|
| StatusNotifierWatcher sender validation | fix applied | ✅ APPLIED (working tree) | G1: Header::sender() on all register/unregister |
| StatusNotifierWatcher owner-keyed registry + purging | fix applied | ✅ APPLIED (working tree) | G1: Registry, purge_owner, NameOwnerChanged listener |
StatusNotifierWatcher bus name → org.kde |
fix applied | ⚠️ NOT APPLIED in code | G1: BUS_NAME still org.freedesktop; only recipe comment changed |
| NM root State enum 0..70 | fix applied | ✅ APPLIED (working tree) | G3: NmState enum, from_device_state |
| OwnedObjectPath types | fix applied | ✅ APPLIED (working tree) | G3: NM interface return types changed |
| Sender validation on invoke actions | fix applied | ✅ APPLIED (working tree) | G2: validate_invoke in notifications |
| Inhibitor lifecycle reaping | fix applied | ❌ NOT APPLIED | G8: no reaping code added to sessiond |
| write_all error propagation | fix applied | ⚠️ PARTIAL (pre-existing) | G7: sessiond has it; authd/udisks/cpufreqd do not |
| Honest capabilities | fix applied | ✅ PRE-EXISTING (unchanged) | G5: already present at HEAD |
| sessiond test env guard | fix applied | ✅ APPLIED (working tree) | G4: kstop_writable() guard in test |
| verify-fork-functions exclusion narrowed | fix applied | ✅ PRE-EXISTING (unchanged) | G6: already narrow at HEAD |
G10. Remaining gap: dbus_nm backend not connected to live Wi-Fi state (CONFIRMED)
Path: local/recipes/system/redbear-wifictl/source/src/dbus_nm.rs
The NM D-Bus interface is a static facade. Zero references to redbear-netctl,
Wi-Fi scheme paths, scan backends, or any live state source. The
register_nm_interface() function creates a hardcoded device
(NmWifiDevice::new_disconnected("wlan0")). request_scan() returns
Ok(()) without performing a scan. The NmWifiDevice struct is purely
in-memory. The dbus-nm feature is not in the default feature set
(default = []), so the entire module is compiled out in default builds.
This is consistent with the plan's deferral of NetworkManager (Red Bear OS
uses redbear-netctl), but the facade's existence should not be mistaken for
a working NM backend. No change in round 2.
G11. Remaining gap: hardcoded root password in redbear-full.toml (CONFIRMED — operator decision, out of scope)
Path: config/redbear-full.toml (lines 102–106)
[users.root]
password = "password"
The root password is the plaintext string "password" — not a salted hash
($6$...). This is a development-time convenience. Replacing it with a proper
SHA-crypt hash (or removing the password line to force first-boot setup) is an
operator decision, tracked separately from the D-Bus integration surface.
No change in round 2; explicitly out of scope per operator.
G12. Remaining gap: NM root StateChanged signal not yet emitted (CONFIRMED)
Path: local/recipes/system/redbear-wifictl/source/src/dbus_nm.rs
No StateChanged signal is defined or emitted on the NM root or device
interface. The NmRoot interface defines properties (state,
wireless_enabled, etc.) but no #[zbus(signal)] declaration. No
PropertiesChanged emission exists either. A comment at line 122 references
StateChanged in the NmState docstring, but no signal code follows.
Clients that poll State will see correct values (thanks to G3's
NmState::from_device_state mapping), but clients that subscribe to
StateChanged or PropertiesChanged for change notification will not receive
updates. No change in round 2.
G13. Remaining gap: Mesa batch pool class math fix (SEPARATE MESA PATCH — not in this round)
Path: local/patches/mesa/ (10 patches)
No patch matching "batch pool" or "class math" exists in local/patches/mesa/.
The closest patch is 26-cs-submit-bidirectional-seqno.patch (batch BO
submission for compute-shader ring seqno synchronization), which is unrelated
to a class/arithmetic fix. This item is tracked as separate Mesa work
outside the D-Bus integration round. The Mesa redox gallium winsys BO byte
count was fixed in an earlier round (per SUPERSEDED-DOC-LOG.md Round 9
post-doc, commit aae6c36b80), but the specific "batch pool class math" issue
referenced by the 5-lane review is either not yet landed or lives in a
different patch series.
G14. Round 2 verification methodology
All findings in this section were verified by reading the actual source files
in the working tree (including uncommitted round-2 changes, confirmed via
git diff), not just the committed HEAD. Five files show uncommitted
modifications relevant to this round:
| File | Change summary |
|---|---|
redbear-statusnotifierwatcher/source/src/main.rs |
Full rewrite: owner-keyed registry, sender validation, NameOwnerChanged purging, input validation, bounded entries |
redbear-statusnotifierwatcher/recipe.toml |
Comment updated: org.freedesktop → org.kde |
redbear-notifications/source/src/main.rs |
NotificationRecord ownership, validate_invoke sender check |
redbear-sessiond/source/src/manager.rs |
Test env guard (kstop_writable) in can_methods_return_na |
redbear-wifictl/source/src/dbus_nm.rs |
NmState enum 0..70, OwnedObjectPath return types |
Host unit tests for all modified daemons pass (cargo test without
--target, the sanctioned test path for pure-logic crates). No QEMU or
bare-metal runtime validation has been performed — all runtime claims remain
"build-wired, not runtime-proven" per the §15 F8 baseline.