D-Bus Phase 3/4: upgrade sessiond, services, add StatusNotifierWatcher, consolidate configs
- redbear-sessiond: add Manager.Inhibit (pipe FD), CanPowerOff/CanReboot/ CanSuspend/CanHibernate/CanHybridSleep/CanSleep (return na), PowerOff/ Reboot/Suspend stubs, GetSessionByPID, ListUsers, ListSeats, ListInhibitors, ActivateSession/LockSession/UnlockSession/TerminateSession - redbear-sessiond: add Session SetIdleHint, SetLockedHint, SetType, Terminate methods; wire PauseDevice/ResumeDevice/Lock/Unlock signal emission via SignalEmitter injection; add dynamic device enumeration scanning /scheme/drm/card* and /dev/input/event* at startup - redbear-sessiond: replace infinite pending() with stoppable shutdown via tokio watch channel + control socket shutdown command - redbear-upower: add Changed signal emission with 30s periodic polling and power state snapshot comparison - redbear-notifications: add ActionInvoked signal, expand capabilities to body + body-markup + actions - redbear-polkit, redbear-udisks: replace pending() with stoppable shutdown via signal handling + watch channel - Add redbear-statusnotifierwatcher: new session bus service implementing org.freedesktop.StatusNotifierWatcher for KDE system tray - Add D-Bus activation file for StatusNotifierWatcher - KWin session.cpp: try LogindSession before NoopSession fallback - Consolidate config profiles: remove obsolete redbear-desktop, redbear-kde, redbear-live-*, redbear-minimal-*, redbear-wayland configs; simplify to three supported targets (redbear-full, redbear-mini, redbear-grub) - Update DBUS-INTEGRATION-PLAN.md and DESKTOP-STACK-CURRENT-STATUS.md with Phase 3/4 fragility assessment, KWin readiness matrix, and completeness gap analysis
This commit is contained in:
@@ -73,7 +73,7 @@ redox-master/
|
|||||||
| Linux driver compat | `docs/04-LINUX-DRIVER-COMPAT.md` | linux-kpi + redox-driver-sys architecture (**GPU and Wi-Fi only — not USB**) |
|
| Linux driver compat | `docs/04-LINUX-DRIVER-COMPAT.md` | linux-kpi + redox-driver-sys architecture (**GPU and Wi-Fi only — not USB**) |
|
||||||
| Build system internals | `src/bin/repo.rs`, `src/lib.rs`, `mk/repo.mk` | Cookbook tool in Rust |
|
| Build system internals | `src/bin/repo.rs`, `src/lib.rs`, `mk/repo.mk` | Cookbook tool in Rust |
|
||||||
| Cross-toolchain setup | `mk/prefix.mk`, `prefix/x86_64-unknown-redox/` | Downloads Clang/LLVM toolchain |
|
| Cross-toolchain setup | `mk/prefix.mk`, `prefix/x86_64-unknown-redox/` | Downloads Clang/LLVM toolchain |
|
||||||
| Display/session surface | `config/redbear-full.toml` | Active desktop/graphics compile surface; `redbear-kde` references elsewhere are historical/staging and not supported compile targets |
|
| Display/session surface | `config/redbear-full.toml` | Active desktop/graphics compile surface |
|
||||||
| GPU/graphics stack | `recipes/libs/mesa/` | OSMesa + LLVMpipe (software only) |
|
| GPU/graphics stack | `recipes/libs/mesa/` | OSMesa + LLVMpipe (software only) |
|
||||||
| GPU hardware drivers | `local/recipes/gpu/redox-drm/source/` | AMD + Intel DRM/KMS via redox-driver-sys |
|
| GPU hardware drivers | `local/recipes/gpu/redox-drm/source/` | AMD + Intel DRM/KMS via redox-driver-sys |
|
||||||
| D-Bus integration | `local/docs/DBUS-INTEGRATION-PLAN.md` | Architecture, gap analysis, phased implementation for KDE Plasma D-Bus |
|
| D-Bus integration | `local/docs/DBUS-INTEGRATION-PLAN.md` | Architecture, gap analysis, phased implementation for KDE Plasma D-Bus |
|
||||||
@@ -93,27 +93,22 @@ echo 'PODMAN_BUILD?=1' > .config # Podman container build
|
|||||||
|
|
||||||
# Build Red Bear OS
|
# Build Red Bear OS
|
||||||
# Supported compile targets:
|
# Supported compile targets:
|
||||||
# redbear-full desktop/graphics harddrive.img
|
# redbear-full desktop/graphics target (harddrive.img or live ISO)
|
||||||
# redbear-live full desktop live ISO (greeter + text fallback)
|
# redbear-mini text-only console/recovery target (harddrive.img or live ISO)
|
||||||
# redbear-live-mini text-only mini live ISO for recovery/bare metal
|
# redbear-grub text-only with GRUB boot manager (live ISO)
|
||||||
# redbear-full-grub desktop target with GRUB boot manager
|
# Desktop/graphics target: redbear-full
|
||||||
# redbear-grub-live-full full desktop live ISO with GRUB
|
# Text-only targets: redbear-mini, redbear-grub
|
||||||
# redbear-grub-live-mini text-only mini live ISO with GRUB
|
make all CONFIG_NAME=redbear-full # Desktop/graphics target → harddrive.img
|
||||||
# Desktop/graphics targets: redbear-full, redbear-full-grub, redbear-live, redbear-grub-live-full
|
make all CONFIG_NAME=redbear-mini # Text-only target → harddrive.img
|
||||||
# Text-only targets: redbear-live-mini, redbear-grub-live-mini
|
make live CONFIG_NAME=redbear-full # Full desktop live ISO
|
||||||
# NOTE: redbear-kde and redbear-live-full are historical/staging, not supported compile targets
|
make live CONFIG_NAME=redbear-mini # Text-only mini live ISO
|
||||||
make all CONFIG_NAME=redbear-full # Desktop/graphics-enabled target → harddrive.img
|
make live CONFIG_NAME=redbear-grub # Text-only mini live ISO with GRUB
|
||||||
make live CONFIG_NAME=redbear-live # Full desktop live ISO (greeter + text fallback)
|
CI=1 make all CONFIG_NAME=redbear-mini # CI mode (disables TUI, for non-interactive)
|
||||||
make live CONFIG_NAME=redbear-live-mini # Text-only mini live ISO for recovery/bare metal
|
|
||||||
make all CONFIG_NAME=redbear-full-grub # Desktop target with GRUB boot manager → harddrive.img
|
|
||||||
make live CONFIG_NAME=redbear-grub-live-full # Full desktop live ISO with GRUB
|
|
||||||
make live CONFIG_NAME=redbear-grub-live-mini # Text-only mini live ISO with GRUB
|
|
||||||
CI=1 make all CONFIG_NAME=redbear-mini # CI mode (disables TUI, for non-interactive)
|
|
||||||
|
|
||||||
# Run
|
# Run
|
||||||
make qemu # Boot in QEMU
|
make qemu # Boot in QEMU
|
||||||
make qemu QEMUFLAGS="-m 4G" # With more RAM
|
make qemu QEMUFLAGS="-m 4G" # With more RAM
|
||||||
make live # Build live ISO for real bare metal → redbear-live.iso
|
make live # Build live ISO for real bare metal
|
||||||
|
|
||||||
# Single recipe
|
# Single recipe
|
||||||
./target/release/repo cook recipes/libs/mesa # Build one recipe
|
./target/release/repo cook recipes/libs/mesa # Build one recipe
|
||||||
@@ -136,7 +131,7 @@ make all
|
|||||||
→ mk/fstools.mk (build cookbook repo binary + fstools)
|
→ mk/fstools.mk (build cookbook repo binary + fstools)
|
||||||
→ mk/repo.mk (repo cook --filesystem=config/*.toml)
|
→ mk/repo.mk (repo cook --filesystem=config/*.toml)
|
||||||
→ For each recipe: fetch source → apply patches → build → stage into sysroot
|
→ For each recipe: fetch source → apply patches → build → stage into sysroot
|
||||||
→ mk/disk.mk (create filesystem.img, harddrive.img, redbear-live.iso)
|
→ mk/disk.mk (create filesystem.img, harddrive.img, redbear-live.iso or harddrive.img)
|
||||||
→ redoxfs-mkfs → redox_installer → bootloader embedding
|
→ redoxfs-mkfs → redox_installer → bootloader embedding
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ Red Bear OS now treats AMD and Intel machines as equal-priority hardware targets
|
|||||||
language in historical integration notes should be read as earlier sequencing context, not as the
|
language in historical integration notes should be read as earlier sequencing context, not as the
|
||||||
current platform policy.
|
current platform policy.
|
||||||
|
|
||||||
The tracked desktop-capable target surface is now `redbear-full` / `redbear-live`, and
|
The tracked desktop-capable target surface is `redbear-full`, and
|
||||||
runtime support claims remain evidence-qualified until compositor/session proof is stronger.
|
runtime support claims remain evidence-qualified until compositor/session proof is stronger.
|
||||||
|
|
||||||
## Historical Phase Snapshot
|
## Historical Phase Snapshot
|
||||||
@@ -176,23 +176,21 @@ Requires a Linux x86_64 host with Rust nightly, QEMU, and standard build tools.
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Non-live (harddrive.img for QEMU / development)
|
# Non-live (harddrive.img for QEMU / development)
|
||||||
make all CONFIG_NAME=redbear-full # Tracked desktop-capable target
|
make all CONFIG_NAME=redbear-full # Desktop/graphics target
|
||||||
make all CONFIG_NAME=redbear-full-grub # Desktop target with GRUB boot manager
|
make all CONFIG_NAME=redbear-mini # Text-only console/recovery target
|
||||||
|
|
||||||
# Live ISO (for real bare metal)
|
# Live ISO (for real bare metal)
|
||||||
make live CONFIG_NAME=redbear-live # Full desktop live ISO (greeter + text fallback)
|
make live CONFIG_NAME=redbear-full # Full desktop live ISO
|
||||||
make live CONFIG_NAME=redbear-live-mini # Text-only mini live ISO for recovery (~384 MiB)
|
make live CONFIG_NAME=redbear-mini # Text-only mini live ISO for recovery
|
||||||
make live CONFIG_NAME=redbear-grub-live-full # Full desktop live ISO with GRUB
|
make live CONFIG_NAME=redbear-grub # Text-only mini live ISO with GRUB
|
||||||
make live CONFIG_NAME=redbear-grub-live-mini # Text-only mini live ISO with GRUB
|
|
||||||
|
|
||||||
# Or use the helper script
|
# Or use the helper script
|
||||||
scripts/build-iso.sh redbear-live # Full desktop live ISO
|
scripts/build-iso.sh redbear-full # Full desktop live ISO
|
||||||
scripts/build-iso.sh redbear-live-mini # Text-only mini
|
scripts/build-iso.sh redbear-mini # Text-only mini (default)
|
||||||
scripts/build-iso.sh redbear-grub-live-full # Full desktop + GRUB
|
scripts/build-iso.sh redbear-grub # Text-only + GRUB
|
||||||
scripts/build-iso.sh redbear-grub-live-mini # Text-only + GRUB
|
|
||||||
|
|
||||||
# QEMU (uses harddrive.img, not live ISO)
|
# QEMU (uses harddrive.img, not live ISO)
|
||||||
make qemu CONFIG_NAME=redbear-full # Boot the tracked desktop-capable target in QEMU
|
make qemu CONFIG_NAME=redbear-full # Boot the desktop target in QEMU
|
||||||
```
|
```
|
||||||
|
|
||||||
Live `.iso` outputs are for real bare-metal boot and install workflows. They are not the virtual/QEMU target surface; use `make qemu` and `harddrive.img`-based flows for virtualization.
|
Live `.iso` outputs are for real bare-metal boot and install workflows. They are not the virtual/QEMU target surface; use `make qemu` and `harddrive.img`-based flows for virtualization.
|
||||||
@@ -202,7 +200,7 @@ Live `.iso` outputs are for real bare-metal boot and install workflows. They are
|
|||||||
Red Bear OS can use GNU GRUB as an alternative boot manager with Linux-compatible CLI:
|
Red Bear OS can use GNU GRUB as an alternative boot manager with Linux-compatible CLI:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
make all CONFIG_NAME=redbear-full-grub # Build broader integration slice with GRUB chainload
|
make all CONFIG_NAME=redbear-grub # Build text-only target with GRUB chainload
|
||||||
./local/scripts/grub-install --target=x86_64-efi --disk-image=build/x86_64/harddrive.img
|
./local/scripts/grub-install --target=x86_64-efi --disk-image=build/x86_64/harddrive.img
|
||||||
./local/scripts/grub-mkconfig -o local/recipes/core/grub/grub.cfg
|
./local/scripts/grub-mkconfig -o local/recipes/core/grub/grub.cfg
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,246 +0,0 @@
|
|||||||
# Red Bear OS Desktop Configuration
|
|
||||||
# Supplementary integration profile beneath the tracked KWin target
|
|
||||||
#
|
|
||||||
# Build: make all CONFIG_NAME=redbear-desktop
|
|
||||||
# Live: make live CONFIG_NAME=redbear-desktop
|
|
||||||
#
|
|
||||||
# This profile remains available for non-KDE-specific integration work.
|
|
||||||
|
|
||||||
include = ["desktop.toml", "redbear-legacy-base.toml", "redbear-legacy-desktop.toml", "redbear-device-services.toml", "redbear-netctl.toml"]
|
|
||||||
|
|
||||||
[general]
|
|
||||||
filesystem_size = 10240
|
|
||||||
|
|
||||||
[packages]
|
|
||||||
# Red Bear OS branding (os-release, hostname, motd)
|
|
||||||
redbear-release = {}
|
|
||||||
|
|
||||||
# Native Redox PCI/USB listing tools (lspci, lsusb)
|
|
||||||
redbear-hwutils = {}
|
|
||||||
|
|
||||||
# Redox-native netctl compatibility command
|
|
||||||
redbear-netctl = {}
|
|
||||||
redbear-netctl-console = {}
|
|
||||||
|
|
||||||
# Native network reporting and connect-scan tools
|
|
||||||
redbear-netstat = {}
|
|
||||||
redbear-traceroute = {}
|
|
||||||
redbear-mtr = {}
|
|
||||||
redbear-nmap = {}
|
|
||||||
|
|
||||||
# Firmware loading + Wi-Fi control plane
|
|
||||||
redbear-firmware = {}
|
|
||||||
firmware-loader = {}
|
|
||||||
redbear-wifictl = {}
|
|
||||||
|
|
||||||
# Input/runtime service prerequisites
|
|
||||||
evdevd = {}
|
|
||||||
udev-shim = {}
|
|
||||||
|
|
||||||
# Diagnostic tool
|
|
||||||
redbear-info = {}
|
|
||||||
|
|
||||||
# Process monitor
|
|
||||||
htop = {}
|
|
||||||
|
|
||||||
# IOMMU validation surface
|
|
||||||
iommu = {}
|
|
||||||
|
|
||||||
# D-Bus IPC and session services
|
|
||||||
dbus = {}
|
|
||||||
redbear-sessiond = {}
|
|
||||||
redbear-dbus-services = {}
|
|
||||||
redbear-notifications = {}
|
|
||||||
redbear-upower = {}
|
|
||||||
redbear-udisks = {}
|
|
||||||
redbear-polkit = {}
|
|
||||||
|
|
||||||
# Terminal file manager (Midnight Commander port)
|
|
||||||
mc = {}
|
|
||||||
|
|
||||||
# Package builder (cub -S/-B/-G CLI)
|
|
||||||
cub = {}
|
|
||||||
|
|
||||||
# Core Red Bear umbrella package
|
|
||||||
redbear-meta = {}
|
|
||||||
|
|
||||||
|
|
||||||
# ── Desktop services (replace legacy desktop-minimal init scripts) ───────────
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/lib/init.d/20_display.service"
|
|
||||||
data = """
|
|
||||||
[unit]
|
|
||||||
description = "Display session service"
|
|
||||||
requires_weak = [
|
|
||||||
]
|
|
||||||
|
|
||||||
[service]
|
|
||||||
cmd = "ion"
|
|
||||||
args = ["-c", "true"]
|
|
||||||
envs = { VT = "3" }
|
|
||||||
type = "oneshot_async"
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/lib/init.d/30_console.service"
|
|
||||||
data = """
|
|
||||||
[unit]
|
|
||||||
description = "Console terminals"
|
|
||||||
requires_weak = [
|
|
||||||
"29_activate_console.service",
|
|
||||||
]
|
|
||||||
|
|
||||||
[service]
|
|
||||||
cmd = "getty"
|
|
||||||
args = ["2"]
|
|
||||||
type = "oneshot_async"
|
|
||||||
respawn = true
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/lib/init.d/29_activate_console.service"
|
|
||||||
data = """
|
|
||||||
[unit]
|
|
||||||
description = "Activate display VT"
|
|
||||||
requires_weak = [
|
|
||||||
"20_display.service",
|
|
||||||
]
|
|
||||||
|
|
||||||
[service]
|
|
||||||
cmd = "inputd"
|
|
||||||
args = ["-A", "3"]
|
|
||||||
type = "oneshot_async"
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/lib/init.d/31_debug_console.service"
|
|
||||||
data = """
|
|
||||||
[unit]
|
|
||||||
description = "Debug console"
|
|
||||||
requires_weak = [
|
|
||||||
"29_activate_console.service",
|
|
||||||
]
|
|
||||||
|
|
||||||
[service]
|
|
||||||
cmd = "getty"
|
|
||||||
args = ["/scheme/debug/no-preserve", "-J"]
|
|
||||||
type = "oneshot_async"
|
|
||||||
respawn = true
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/lib/init.d/13_iommu.service"
|
|
||||||
data = """
|
|
||||||
[unit]
|
|
||||||
description = "IOMMU DMA remapping daemon"
|
|
||||||
requires_weak = [
|
|
||||||
"00_pcid-spawner.service",
|
|
||||||
]
|
|
||||||
|
|
||||||
[service]
|
|
||||||
cmd = "/usr/bin/iommu"
|
|
||||||
type = "oneshot_async"
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/lib/init.d/12_dbus.service"
|
|
||||||
data = """
|
|
||||||
[unit]
|
|
||||||
description = "D-Bus system bus"
|
|
||||||
requires_weak = [
|
|
||||||
"12_boot-late.target",
|
|
||||||
]
|
|
||||||
|
|
||||||
[service]
|
|
||||||
cmd = "ion"
|
|
||||||
args = [
|
|
||||||
"-c",
|
|
||||||
"mkdir -p /var/lib/dbus /run/dbus; rm -f /run/dbus/pid; dbus-uuidgen --ensure; dbus-daemon --system",
|
|
||||||
]
|
|
||||||
type = "oneshot_async"
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/lib/init.d/13_redbear-sessiond.service"
|
|
||||||
data = """
|
|
||||||
[unit]
|
|
||||||
description = "Red Bear session broker (org.freedesktop.login1)"
|
|
||||||
requires_weak = [
|
|
||||||
"12_dbus.service",
|
|
||||||
]
|
|
||||||
|
|
||||||
[service]
|
|
||||||
cmd = "ion"
|
|
||||||
args = [
|
|
||||||
"-c",
|
|
||||||
"redbear-sessiond",
|
|
||||||
]
|
|
||||||
type = "oneshot_async"
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/lib/init.d/14_redbear-upower.service"
|
|
||||||
data = """
|
|
||||||
[unit]
|
|
||||||
description = "UPower D-Bus service (org.freedesktop.UPower)"
|
|
||||||
requires_weak = [
|
|
||||||
"12_dbus.service",
|
|
||||||
]
|
|
||||||
|
|
||||||
[service]
|
|
||||||
cmd = "ion"
|
|
||||||
args = [
|
|
||||||
"-c",
|
|
||||||
"redbear-upower",
|
|
||||||
]
|
|
||||||
type = "oneshot_async"
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/lib/init.d/14_redbear-udisks.service"
|
|
||||||
data = """
|
|
||||||
[unit]
|
|
||||||
description = "UDisks2 D-Bus service (org.freedesktop.UDisks2)"
|
|
||||||
requires_weak = [
|
|
||||||
"12_dbus.service",
|
|
||||||
]
|
|
||||||
|
|
||||||
[service]
|
|
||||||
cmd = "ion"
|
|
||||||
args = [
|
|
||||||
"-c",
|
|
||||||
"redbear-udisks",
|
|
||||||
]
|
|
||||||
type = "oneshot_async"
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/lib/init.d/14_redbear-polkit.service"
|
|
||||||
data = """
|
|
||||||
[unit]
|
|
||||||
description = "PolicyKit1 D-Bus service (org.freedesktop.PolicyKit1)"
|
|
||||||
requires_weak = [
|
|
||||||
"12_dbus.service",
|
|
||||||
]
|
|
||||||
|
|
||||||
[service]
|
|
||||||
cmd = "ion"
|
|
||||||
args = [
|
|
||||||
"-c",
|
|
||||||
"redbear-polkit",
|
|
||||||
]
|
|
||||||
type = "oneshot_async"
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/var/lib/dbus"
|
|
||||||
data = ""
|
|
||||||
directory = true
|
|
||||||
mode = 0o755
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/run/dbus"
|
|
||||||
data = ""
|
|
||||||
directory = true
|
|
||||||
mode = 0o755
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
# Red Bear OS Full Configuration with GRUB Boot Manager
|
|
||||||
# Desktop + RBOS branding + GRUB chainload
|
|
||||||
#
|
|
||||||
# Build: make all CONFIG_NAME=redbear-full-grub
|
|
||||||
#
|
|
||||||
# This config adds GRUB as boot manager (Phase 2 installer-native).
|
|
||||||
# GRUB presents a menu and chainloads the Redox bootloader.
|
|
||||||
# Requires: efi_partition_size >= 8 (16 recommended for GRUB + Redox bootloader + margin)
|
|
||||||
|
|
||||||
include = ["redbear-full.toml", "redbear-grub.toml"]
|
|
||||||
+157
-357
@@ -1,15 +1,13 @@
|
|||||||
# Red Bear OS Full Configuration
|
# Red Bear OS Full Configuration
|
||||||
# Primary desktop/session target: Wayland + KWin/KDE session surface on Red Bear OS.
|
# Desktop/graphics ISO for bare metal and QEMU.
|
||||||
# Build: make all CONFIG_NAME=redbear-full
|
|
||||||
# Live: make live CONFIG_NAME=redbear-live-full # bare-metal live ISO only
|
|
||||||
#
|
#
|
||||||
# This is the only active full desktop target. Wayland and KDE package/runtime surfaces are folded
|
# Build: make live CONFIG_NAME=redbear-full
|
||||||
# here instead of being split across redbear-wayland and redbear-kde.
|
# QEMU: make all CONFIG_NAME=redbear-full && make qemu
|
||||||
# GPU driver stack ships through redbear-meta for this profile.
|
#
|
||||||
# redox-drm now carries the runtime/package dependency on the AMD backend library.
|
# Extends redbear-mini with the full desktop/graphics stack:
|
||||||
# Runtime/session claims still remain evidence-qualified until compositor/session proof is strong.
|
# Wayland, Qt6, KF6, KWin, Mesa, DRM drivers, firmware, greeter.
|
||||||
|
|
||||||
include = ["desktop.toml", "redbear-legacy-base.toml", "redbear-legacy-desktop.toml", "redbear-device-services.toml", "redbear-netctl.toml", "redbear-greeter-services.toml"]
|
include = ["redbear-mini.toml"]
|
||||||
|
|
||||||
[general]
|
[general]
|
||||||
filesystem_size = 4096
|
filesystem_size = 4096
|
||||||
@@ -23,73 +21,20 @@ home = "/nonexistent"
|
|||||||
shell = "/usr/bin/ion"
|
shell = "/usr/bin/ion"
|
||||||
|
|
||||||
[packages]
|
[packages]
|
||||||
# Red Bear OS branding (os-release, hostname, motd)
|
# Firmware loading
|
||||||
redbear-release = {}
|
|
||||||
|
|
||||||
# Exclude inherited legacy desktop packages from the tracked KWin/Wayland target
|
|
||||||
orbdata = "ignore"
|
|
||||||
orbital = "ignore"
|
|
||||||
orbterm = "ignore"
|
|
||||||
orbutils = "ignore"
|
|
||||||
cosmic-edit = "ignore"
|
|
||||||
cosmic-files = "ignore"
|
|
||||||
cosmic-icons = "ignore"
|
|
||||||
cosmic-term = "ignore"
|
|
||||||
|
|
||||||
# Native Redox PCI/USB listing tools (lspci, lsusb)
|
|
||||||
redbear-hwutils = {}
|
|
||||||
|
|
||||||
# Redox-native netctl compatibility command
|
|
||||||
redbear-netctl = {}
|
|
||||||
redbear-netctl-console = {}
|
|
||||||
|
|
||||||
# Native network reporting and connect-scan tools
|
|
||||||
redbear-netstat = {}
|
|
||||||
redbear-traceroute = {}
|
|
||||||
redbear-mtr = {}
|
|
||||||
redbear-nmap = {}
|
|
||||||
|
|
||||||
# Package builder / recipe utility
|
|
||||||
cub = {}
|
|
||||||
|
|
||||||
# Terminal file manager (Midnight Commander port)
|
|
||||||
mc = {}
|
|
||||||
|
|
||||||
# ext4 filesystem support (our custom port)
|
|
||||||
ext4d = {}
|
|
||||||
|
|
||||||
# Firmware loading + Wi-Fi control plane
|
|
||||||
redbear-firmware = {}
|
redbear-firmware = {}
|
||||||
firmware-loader = {}
|
firmware-loader = {}
|
||||||
redbear-wifictl = {}
|
|
||||||
|
|
||||||
# Input layer
|
# GPU/graphics stack
|
||||||
evdevd = {}
|
redox-drm = {}
|
||||||
udev-shim = {}
|
mesa = {}
|
||||||
|
libdrm = {}
|
||||||
# Desktop/session plumbing
|
|
||||||
dbus = {}
|
|
||||||
redbear-sessiond = {}
|
|
||||||
redbear-dbus-services = {}
|
|
||||||
redbear-notifications = {}
|
|
||||||
redbear-upower = {}
|
|
||||||
redbear-udisks = {}
|
|
||||||
redbear-polkit = {}
|
|
||||||
|
|
||||||
# IOMMU DMA remapping daemon
|
|
||||||
iommu = {}
|
|
||||||
|
|
||||||
# Diagnostic tool
|
|
||||||
redbear-info = {}
|
|
||||||
|
|
||||||
# Process monitor
|
|
||||||
htop = {}
|
|
||||||
|
|
||||||
# Wayland protocol
|
# Wayland protocol
|
||||||
libwayland = {}
|
libwayland = {}
|
||||||
wayland-protocols = {}
|
wayland-protocols = {}
|
||||||
|
|
||||||
# Keyboard support
|
# Keyboard/input
|
||||||
libxkbcommon = {}
|
libxkbcommon = {}
|
||||||
xkeyboard-config = {}
|
xkeyboard-config = {}
|
||||||
libevdev = {}
|
libevdev = {}
|
||||||
@@ -105,15 +50,13 @@ qtsvg = {}
|
|||||||
qtwayland = {}
|
qtwayland = {}
|
||||||
qt6-wayland-smoke = {}
|
qt6-wayland-smoke = {}
|
||||||
|
|
||||||
# KF6 Frameworks — Tier 1
|
# KF6 Frameworks
|
||||||
kf6-extra-cmake-modules = {}
|
kf6-extra-cmake-modules = {}
|
||||||
kf6-kcoreaddons = {}
|
kf6-kcoreaddons = {}
|
||||||
kf6-kconfig = {}
|
kf6-kconfig = {}
|
||||||
kf6-ki18n = {}
|
kf6-ki18n = {}
|
||||||
kf6-kcolorscheme = {}
|
kf6-kcolorscheme = {}
|
||||||
kf6-kauth = {}
|
kf6-kauth = {}
|
||||||
|
|
||||||
# KF6 Frameworks — KWin session-surface chain
|
|
||||||
kf6-kwindowsystem = {}
|
kf6-kwindowsystem = {}
|
||||||
kf6-knotifications = {}
|
kf6-knotifications = {}
|
||||||
kf6-kconfigwidgets = {}
|
kf6-kconfigwidgets = {}
|
||||||
@@ -133,24 +76,50 @@ kdecoration = {}
|
|||||||
# KWin Wayland compositor
|
# KWin Wayland compositor
|
||||||
kwin = {}
|
kwin = {}
|
||||||
|
|
||||||
# Graphics
|
# Greeter/login stack
|
||||||
redox-drm = {}
|
redbear-authd = {}
|
||||||
mesa = {}
|
redbear-session-launch = {}
|
||||||
libdrm = {}
|
redbear-greeter = {}
|
||||||
|
|
||||||
# Core Red Bear umbrella package
|
# Core Red Bear umbrella package
|
||||||
redbear-meta = {}
|
redbear-meta = {}
|
||||||
|
|
||||||
# Firmware directory for AMD/Intel GPU blobs
|
# Desktop fonts and icons
|
||||||
|
dejavu = {}
|
||||||
|
freefont = {}
|
||||||
|
hicolor-icon-theme = {}
|
||||||
|
pop-icon-theme = {}
|
||||||
|
|
||||||
|
# Suppress legacy desktop packages
|
||||||
|
orbdata = "ignore"
|
||||||
|
orbital = "ignore"
|
||||||
|
orbterm = "ignore"
|
||||||
|
orbutils = "ignore"
|
||||||
|
cosmic-edit = "ignore"
|
||||||
|
cosmic-files = "ignore"
|
||||||
|
cosmic-icons = "ignore"
|
||||||
|
cosmic-term = "ignore"
|
||||||
|
|
||||||
[[files]]
|
[[files]]
|
||||||
path = "/lib/firmware/amdgpu"
|
path = "/lib/firmware/amdgpu"
|
||||||
data = ""
|
data = ""
|
||||||
directory = true
|
directory = true
|
||||||
mode = 0o755
|
mode = 0o755
|
||||||
|
|
||||||
# Greeter/login service wiring now lives in config/redbear-greeter-services.toml, which is
|
[[files]]
|
||||||
# included above so the full desktop target has a single source of truth for display/fallback
|
path = "/usr/lib/fonts"
|
||||||
# session services.
|
data = "/usr/share/fonts"
|
||||||
|
symlink = true
|
||||||
|
|
||||||
|
[[files]]
|
||||||
|
path = "/usr/lib/init.d/05_boot-essential.target"
|
||||||
|
data = """
|
||||||
|
[unit]
|
||||||
|
description = "Boot essential services target"
|
||||||
|
requires_weak = [
|
||||||
|
"00_base.target",
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
|
||||||
[[files]]
|
[[files]]
|
||||||
path = "/usr/lib/init.d/13_iommu.service"
|
path = "/usr/lib/init.d/13_iommu.service"
|
||||||
@@ -185,7 +154,6 @@ args = [
|
|||||||
type = "oneshot_async"
|
type = "oneshot_async"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
[[files]]
|
[[files]]
|
||||||
path = "/usr/lib/init.d/13_redbear-sessiond.service"
|
path = "/usr/lib/init.d/13_redbear-sessiond.service"
|
||||||
data = """
|
data = """
|
||||||
@@ -275,293 +243,125 @@ type = "oneshot_async"
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
[[files]]
|
[[files]]
|
||||||
path = "/var/lib/dbus"
|
path = "/usr/lib/init.d/19_redbear-authd.service"
|
||||||
data = ""
|
|
||||||
directory = true
|
|
||||||
mode = 0o755
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/run/dbus"
|
|
||||||
data = ""
|
|
||||||
directory = true
|
|
||||||
mode = 0o755
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/lib/fonts"
|
|
||||||
data = "/usr/share/fonts"
|
|
||||||
symlink = true
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/bin/redbear-validation-session"
|
|
||||||
mode = 0o755
|
|
||||||
data = """
|
data = """
|
||||||
#!/usr/bin/env sh
|
[unit]
|
||||||
|
description = "Red Bear authentication daemon"
|
||||||
|
requires_weak = [
|
||||||
|
"12_dbus.service",
|
||||||
|
]
|
||||||
|
|
||||||
export DISPLAY=""
|
[service]
|
||||||
export HOME="${HOME:-/home/root}"
|
cmd = "ion"
|
||||||
export USER="${USER:-root}"
|
args = [
|
||||||
export LOGNAME="${LOGNAME:-$USER}"
|
"-c",
|
||||||
export WAYLAND_DISPLAY="${WAYLAND_DISPLAY:-wayland-0}"
|
"redbear-authd",
|
||||||
export XDG_SESSION_TYPE=wayland
|
]
|
||||||
export LIBSEAT_BACKEND=seatd
|
type = "oneshot_async"
|
||||||
export SEATD_SOCK=/run/seatd.sock
|
|
||||||
export QT_PLUGIN_PATH=/usr/plugins
|
|
||||||
export QT_QPA_PLATFORM_PLUGIN_PATH=/usr/plugins/platforms
|
|
||||||
export QML2_IMPORT_PATH=/usr/qml
|
|
||||||
export RUST_BACKTRACE=full
|
|
||||||
export RUST_LOG=debug
|
|
||||||
export XCURSOR_THEME=Pop
|
|
||||||
export 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
|
|
||||||
|
|
||||||
wait_for_path() {
|
|
||||||
target="$1"
|
|
||||||
attempts=0
|
|
||||||
while [ "$attempts" -lt 30 ]; do
|
|
||||||
if [ -e "$target" ]; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
attempts=$((attempts + 1))
|
|
||||||
sleep 1
|
|
||||||
done
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if ! wait_for_path /run/dbus/system_bus_socket; then
|
|
||||||
echo "system D-Bus socket did not appear" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
sleep 2
|
|
||||||
|
|
||||||
wait_for_wayland_socket() {
|
|
||||||
socket_path="$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY"
|
|
||||||
attempts=0
|
|
||||||
while [ "$attempts" -lt 30 ]; do
|
|
||||||
if [ -e "$socket_path" ]; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
if ! kill -0 "$kwin_pid" 2>/scheme/null; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
attempts=$((attempts + 1))
|
|
||||||
sleep 1
|
|
||||||
done
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if [ -z "${DBUS_SESSION_BUS_ADDRESS:-}" ]; then
|
|
||||||
eval "$(dbus-launch --sh-syntax)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
validation_request="/run/redbear-kde-session.validation-request"
|
|
||||||
validation_success="/run/redbear-kde-session.validation-success"
|
|
||||||
|
|
||||||
if [ -f "$validation_request" ]; then
|
|
||||||
{
|
|
||||||
echo "user=$USER"
|
|
||||||
echo "runtime=$XDG_RUNTIME_DIR"
|
|
||||||
echo "wayland=$WAYLAND_DISPLAY"
|
|
||||||
} > "$validation_success"
|
|
||||||
rm -f "$validation_request"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
dbus-update-activation-environment \
|
|
||||||
DBUS_SESSION_BUS_ADDRESS \
|
|
||||||
DBUS_SESSION_BUS_PID \
|
|
||||||
WAYLAND_DISPLAY \
|
|
||||||
XDG_SESSION_TYPE \
|
|
||||||
XDG_RUNTIME_DIR \
|
|
||||||
DISPLAY \
|
|
||||||
HOME \
|
|
||||||
USER
|
|
||||||
|
|
||||||
if [ -d /usr/share/glib-2.0/schemas ]; then
|
|
||||||
glib-compile-schemas /usr/share/glib-2.0/schemas/
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$KWIN_DRM_DEVICES" ]; then
|
|
||||||
kwin_wayland_wrapper --drm &
|
|
||||||
else
|
|
||||||
echo "redbear-validation-session: using virtual KWin backend (set KWIN_DRM_DEVICES to enable DRM)" >&2
|
|
||||||
kwin_wayland_wrapper --virtual &
|
|
||||||
fi
|
|
||||||
kwin_pid=$!
|
|
||||||
|
|
||||||
if ! wait_for_wayland_socket; then
|
|
||||||
echo "kwin_wayland failed to expose $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
/usr/bin/wayland-session
|
|
||||||
smoke_exit=$?
|
|
||||||
|
|
||||||
echo "wayland-session exited with code $smoke_exit"
|
|
||||||
|
|
||||||
# 60-second KWin survival verdict
|
|
||||||
survival_ok="$HOME/.kwin-60s-survival.ok"
|
|
||||||
survival_err="$HOME/.kwin-60s-survival.err"
|
|
||||||
rm -f "$survival_ok" "$survival_err"
|
|
||||||
|
|
||||||
elapsed=0
|
|
||||||
while kill -0 "$kwin_pid" 2>/dev/null; do
|
|
||||||
if [ "$elapsed" -ge 60 ]; then
|
|
||||||
echo "KWin survived 60 seconds (pid=$kwin_pid)" > "$survival_ok"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
sleep 1
|
|
||||||
elapsed=$((elapsed + 1))
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ ! -f "$survival_ok" ]; then
|
|
||||||
echo "KWin died before 60 seconds (pid=$kwin_pid, elapsed=${elapsed}s)" > "$survival_err"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "redbear-validation-session: complete (smoke_exit=$smoke_exit, survival=$([ -f "$survival_ok" ] && echo ok || echo failed))"
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
[[files]]
|
[[files]]
|
||||||
path = "/usr/bin/wayland-session"
|
path = "/usr/lib/init.d/20_greeter.service"
|
||||||
mode = 0o755
|
|
||||||
data = """
|
data = """
|
||||||
#!/usr/bin/env ion
|
[unit]
|
||||||
|
description = "Red Bear greeter service"
|
||||||
|
requires_weak = [
|
||||||
|
"12_dbus.service",
|
||||||
|
"13_redbear-sessiond.service",
|
||||||
|
"13_seatd.service",
|
||||||
|
"19_redbear-authd.service",
|
||||||
|
]
|
||||||
|
|
||||||
printenv
|
[service]
|
||||||
let session_started = "$HOME/.wayland-session.started"
|
cmd = "/usr/bin/redbear-greeterd"
|
||||||
rm -f $session_started
|
envs = { VT = "3", REDBEAR_GREETER_USER = "greeter" }
|
||||||
echo "started" > $session_started
|
type = "oneshot_async"
|
||||||
export QT_PLUGIN_PATH=/usr/plugins
|
|
||||||
export QT_QPA_PLATFORM_PLUGIN_PATH=/usr/plugins/platforms
|
|
||||||
export QML2_IMPORT_PATH=/usr/qml
|
|
||||||
let smoke_ok = "$HOME/.qt6-wayland-smoke.ok"
|
|
||||||
let smoke_err = "$HOME/.qt6-wayland-smoke.err"
|
|
||||||
let smoke_log = "$HOME/.qt6-wayland-smoke.log"
|
|
||||||
let bootstrap_ok = "$HOME/.qt6-bootstrap-minimal.ok"
|
|
||||||
let bootstrap_log = "$HOME/.qt6-bootstrap-minimal.log"
|
|
||||||
let plugin_ok = "$HOME/.qt6-plugin-minimal.ok"
|
|
||||||
let plugin_err = "$HOME/.qt6-plugin-minimal.err"
|
|
||||||
let plugin_log = "$HOME/.qt6-plugin-minimal.log"
|
|
||||||
let smoke_minimal_ok = "$HOME/.qt6-wayland-smoke-minimal.ok"
|
|
||||||
let smoke_offscreen_ok = "$HOME/.qt6-wayland-smoke-offscreen.ok"
|
|
||||||
let smoke_wayland_ok = "$HOME/.qt6-wayland-smoke-wayland.ok"
|
|
||||||
let smoke_minimal_log = "$HOME/.qt6-wayland-smoke-minimal.log"
|
|
||||||
let smoke_offscreen_log = "$HOME/.qt6-wayland-smoke-offscreen.log"
|
|
||||||
let smoke_wayland_log = "$HOME/.qt6-wayland-smoke-wayland.log"
|
|
||||||
rm -f $smoke_ok $smoke_err
|
|
||||||
rm -f $smoke_log
|
|
||||||
rm -f $bootstrap_ok $bootstrap_log
|
|
||||||
rm -f $plugin_ok $plugin_err $plugin_log
|
|
||||||
rm -f $smoke_minimal_ok $smoke_offscreen_ok $smoke_wayland_ok
|
|
||||||
rm -f $smoke_minimal_log $smoke_offscreen_log $smoke_wayland_log
|
|
||||||
if which qt6-wayland-smoke >/scheme/null
|
|
||||||
if env LD_DEBUG=all QT_DEBUG_PLUGINS=1 QT_QPA_PLATFORM=minimal qt6-bootstrap-check > $bootstrap_log ^> $bootstrap_log
|
|
||||||
touch $bootstrap_ok
|
|
||||||
else
|
|
||||||
if test -f $bootstrap_log
|
|
||||||
cat $bootstrap_log
|
|
||||||
end
|
|
||||||
echo "qt6-bootstrap-check minimal failed; see $bootstrap_log" > $smoke_err
|
|
||||||
end
|
|
||||||
|
|
||||||
if env LD_DEBUG=all QT_DEBUG_PLUGINS=1 QT_PLUGIN_PATH=/usr/plugins QT_QPA_PLATFORM_PLUGIN_PATH=/usr/plugins/platforms qt6-plugin-check /usr/plugins/platforms/libqminimal.so > $plugin_log ^> $plugin_log
|
|
||||||
touch $plugin_ok
|
|
||||||
else
|
|
||||||
if test -f $plugin_log
|
|
||||||
cat $plugin_log
|
|
||||||
end
|
|
||||||
echo "qt6-plugin-check failed; see $plugin_log" > $plugin_err
|
|
||||||
echo "qt6-plugin-check failed; see $plugin_log" > $smoke_err
|
|
||||||
end
|
|
||||||
|
|
||||||
if env QT_DEBUG_PLUGINS=1 QT_QPA_PLATFORM=minimal qt6-wayland-smoke > $smoke_minimal_log ^> $smoke_minimal_log
|
|
||||||
touch $smoke_minimal_ok
|
|
||||||
else
|
|
||||||
echo "qt6-wayland-smoke minimal failed; see $smoke_minimal_log" > $smoke_err
|
|
||||||
end
|
|
||||||
|
|
||||||
if env QT_DEBUG_PLUGINS=1 QT_QPA_PLATFORM=offscreen qt6-wayland-smoke > $smoke_offscreen_log ^> $smoke_offscreen_log
|
|
||||||
touch $smoke_offscreen_ok
|
|
||||||
else
|
|
||||||
echo "qt6-wayland-smoke offscreen failed; see $smoke_offscreen_log" > $smoke_err
|
|
||||||
end
|
|
||||||
|
|
||||||
if env QT_DEBUG_PLUGINS=1 QT_QPA_PLATFORM=wayland qt6-wayland-smoke > $smoke_wayland_log ^> $smoke_wayland_log
|
|
||||||
touch $smoke_wayland_ok
|
|
||||||
touch $smoke_ok
|
|
||||||
else
|
|
||||||
echo "qt6-wayland-smoke wayland failed; see $smoke_wayland_log" > $smoke_err
|
|
||||||
end
|
|
||||||
end
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
[[files]]
|
[[files]]
|
||||||
path = "/usr/bin/redbear-kde-session"
|
path = "/usr/lib/init.d/29_activate_console.service"
|
||||||
mode = 0o755
|
|
||||||
data = """
|
data = """
|
||||||
#!/usr/bin/sh
|
[unit]
|
||||||
|
description = "Activate fallback console VT"
|
||||||
|
requires_weak = [
|
||||||
|
"05_boot-essential.target",
|
||||||
|
]
|
||||||
|
|
||||||
export DISPLAY=""
|
[service]
|
||||||
export WAYLAND_DISPLAY="${WAYLAND_DISPLAY:-wayland-0}"
|
cmd = "inputd"
|
||||||
export XDG_SESSION_TYPE=wayland
|
args = ["-A", "2"]
|
||||||
export KDE_FULL_SESSION=true
|
type = "oneshot_async"
|
||||||
export XDG_CURRENT_DESKTOP=KDE
|
"""
|
||||||
export LIBSEAT_BACKEND=seatd
|
|
||||||
export SEATD_SOCK=/run/seatd.sock
|
[[files]]
|
||||||
export QT_PLUGIN_PATH="${QT_PLUGIN_PATH:-/usr/plugins}"
|
path = "/usr/lib/init.d/30_console.service"
|
||||||
export QT_QPA_PLATFORM_PLUGIN_PATH="${QT_QPA_PLATFORM_PLUGIN_PATH:-/usr/plugins/platforms}"
|
data = """
|
||||||
export QML2_IMPORT_PATH="${QML2_IMPORT_PATH:-/usr/qml}"
|
[unit]
|
||||||
export XCURSOR_THEME="${XCURSOR_THEME:-Pop}"
|
description = "Console terminals"
|
||||||
export XKB_CONFIG_ROOT="${XKB_CONFIG_ROOT:-/usr/share/X11/xkb}"
|
requires_weak = [
|
||||||
|
"29_activate_console.service",
|
||||||
if [ -z "${XDG_RUNTIME_DIR:-}" ]; then
|
]
|
||||||
export XDG_RUNTIME_DIR="/tmp/run/user/$(id -u)"
|
|
||||||
fi
|
[service]
|
||||||
|
cmd = "getty"
|
||||||
mkdir -p "$XDG_RUNTIME_DIR"
|
args = ["2"]
|
||||||
chmod 700 "$XDG_RUNTIME_DIR" 2>/dev/null || true
|
type = "oneshot_async"
|
||||||
|
respawn = true
|
||||||
if [ -z "${DBUS_SESSION_BUS_ADDRESS:-}" ]; then
|
"""
|
||||||
eval "$(dbus-launch --sh-syntax)"
|
|
||||||
fi
|
[[files]]
|
||||||
|
path = "/usr/lib/init.d/31_debug_console.service"
|
||||||
validation_request="/run/redbear-kde-session.validation-request"
|
data = """
|
||||||
validation_success="/run/redbear-kde-session.validation-success"
|
[unit]
|
||||||
|
description = "Debug console"
|
||||||
if [ -f "$validation_request" ]; then
|
requires_weak = [
|
||||||
{
|
"29_activate_console.service",
|
||||||
echo "user=$USER"
|
]
|
||||||
echo "runtime=$XDG_RUNTIME_DIR"
|
|
||||||
echo "wayland=$WAYLAND_DISPLAY"
|
[service]
|
||||||
} > "$validation_success"
|
cmd = "getty"
|
||||||
rm -f "$validation_request"
|
args = ["/scheme/debug/no-preserve", "-J"]
|
||||||
exit 0
|
type = "oneshot_async"
|
||||||
fi
|
respawn = true
|
||||||
|
"""
|
||||||
dbus-update-activation-environment \
|
|
||||||
DBUS_SESSION_BUS_ADDRESS \
|
[users.greeter]
|
||||||
DBUS_SESSION_BUS_PID \
|
password = ""
|
||||||
WAYLAND_DISPLAY \
|
uid = 101
|
||||||
XDG_SESSION_ID \
|
gid = 101
|
||||||
XDG_SEAT \
|
name = "greeter"
|
||||||
XDG_SESSION_TYPE \
|
home = "/nonexistent"
|
||||||
XDG_RUNTIME_DIR \
|
shell = "/usr/bin/ion"
|
||||||
XDG_CURRENT_DESKTOP \
|
|
||||||
KDE_FULL_SESSION \
|
[groups.greeter]
|
||||||
DISPLAY \
|
gid = 101
|
||||||
HOME \
|
members = ["greeter"]
|
||||||
USER
|
|
||||||
|
[[files]]
|
||||||
if [ -n "$KWIN_DRM_DEVICES" ]; then
|
path = "/etc/pcid.d/ihdgd.toml"
|
||||||
exec kwin_wayland_wrapper --drm
|
data = """
|
||||||
else
|
[[drivers]]
|
||||||
echo "redbear-kde-session: using virtual KWin backend (set KWIN_DRM_DEVICES to enable DRM)" >&2
|
name = "Intel GPU (VGA compatible)"
|
||||||
exec kwin_wayland_wrapper --virtual
|
class = 0x03
|
||||||
fi
|
vendor = 0x8086
|
||||||
|
subclass = 0x00
|
||||||
|
command = ["redox-drm"]
|
||||||
|
|
||||||
|
[[drivers]]
|
||||||
|
name = "Intel GPU (3D controller)"
|
||||||
|
class = 0x03
|
||||||
|
vendor = 0x8086
|
||||||
|
subclass = 0x02
|
||||||
|
command = ["redox-drm"]
|
||||||
|
"""
|
||||||
|
|
||||||
|
[[files]]
|
||||||
|
path = "/etc/pcid.d/virtio-gpud.toml"
|
||||||
|
data = """
|
||||||
|
[[drivers]]
|
||||||
|
name = "VirtIO GPU"
|
||||||
|
class = 0x03
|
||||||
|
vendor = 0x1af4
|
||||||
|
subclass = 0x00
|
||||||
|
command = ["redox-drm"]
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
# Red Bear OS GRUB Live Full Configuration
|
|
||||||
# Canonical GRUB-backed live ISO for the full desktop/session target.
|
|
||||||
#
|
|
||||||
# Build: make live CONFIG_NAME=redbear-grub-live-full
|
|
||||||
#
|
|
||||||
# Boot flow: UEFI → GRUB (menu) → chainload EFI/REDBEAR/redbear.efi → Redox bootloader → kernel
|
|
||||||
# Session: graphical greeter on VT 3, text login fallback on VT 2, debug console on /scheme/debug
|
|
||||||
#
|
|
||||||
# The installer reads bootloader = "grub" from this config and writes:
|
|
||||||
# EFI/BOOT/BOOTX64.EFI — GRUB EFI binary (primary bootloader)
|
|
||||||
# EFI/BOOT/grub.cfg — GRUB menu config
|
|
||||||
# EFI/REDBEAR/redbear.efi — Redox bootloader (chainload target)
|
|
||||||
|
|
||||||
include = ["redbear-live.toml", "redbear-grub.toml"]
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
# Red Bear OS GRUB Live Mini Configuration
|
|
||||||
# Canonical GRUB-backed live ISO for the stripped console/recovery target.
|
|
||||||
#
|
|
||||||
# Build: make live CONFIG_NAME=redbear-grub-live-mini
|
|
||||||
|
|
||||||
include = ["redbear-live-mini.toml", "redbear-grub.toml"]
|
|
||||||
|
|
||||||
[general]
|
|
||||||
efi_partition_size = 16
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Red Bear OS shared GRUB policy fragment
|
||||||
|
# Use with any redbear-* profile to make GRUB first-class in installer flows.
|
||||||
|
|
||||||
|
[general]
|
||||||
|
bootloader = "grub"
|
||||||
|
efi_partition_size = 16
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
grub = {}
|
||||||
@@ -1,11 +1,16 @@
|
|||||||
# Red Bear OS shared GRUB policy fragment
|
# Red Bear OS GRUB Configuration
|
||||||
# Use with any redbear-* profile to make GRUB first-class in installer flows.
|
# Text-only ISO with GRUB boot manager for bare metal.
|
||||||
|
#
|
||||||
|
# Build: make live CONFIG_NAME=redbear-grub
|
||||||
|
#
|
||||||
|
# Identical to redbear-mini but uses GNU GRUB as the boot manager
|
||||||
|
# instead of the Redox EFI bootloader.
|
||||||
|
|
||||||
|
include = ["redbear-mini.toml", "redbear-grub-policy.toml"]
|
||||||
|
|
||||||
[general]
|
[general]
|
||||||
bootloader = "grub"
|
bootloader = "grub"
|
||||||
# Keep ESP large enough for GRUB EFI image + Red Bear bootloader + future growth.
|
|
||||||
efi_partition_size = 16
|
efi_partition_size = 16
|
||||||
|
|
||||||
[packages]
|
[packages]
|
||||||
# Ensure GRUB artifacts are present for installer-native chainload layout.
|
|
||||||
grub = {}
|
grub = {}
|
||||||
|
|||||||
@@ -1,381 +0,0 @@
|
|||||||
# Red Bear OS Target Wayland Desktop Configuration
|
|
||||||
# Build: make all CONFIG_NAME=redbear-kde
|
|
||||||
# Live: make live CONFIG_NAME=redbear-kde
|
|
||||||
#
|
|
||||||
# Intended desktop direction: KWin Wayland session on Red Bear OS
|
|
||||||
# Tracked default desktop target for Red Bear OS
|
|
||||||
# Current state: KWin + KF6 + Qt6 + Mesa + D-Bus + seatd
|
|
||||||
# Runtime compositor/session proof is still required for broader support claims
|
|
||||||
# Future: add plasma-workspace, plasma-desktop when their deps are resolved
|
|
||||||
|
|
||||||
include = ["desktop.toml", "redbear-legacy-base.toml", "redbear-legacy-desktop.toml", "redbear-device-services.toml", "redbear-netctl.toml"]
|
|
||||||
|
|
||||||
[general]
|
|
||||||
filesystem_size = 4096
|
|
||||||
|
|
||||||
[users.messagebus]
|
|
||||||
uid = 100
|
|
||||||
gid = 100
|
|
||||||
name = "messagebus"
|
|
||||||
home = "/nonexistent"
|
|
||||||
shell = "/usr/bin/ion"
|
|
||||||
|
|
||||||
[packages]
|
|
||||||
# Red Bear OS branding
|
|
||||||
redbear-release = {}
|
|
||||||
|
|
||||||
# Exclude inherited legacy desktop packages from the tracked KWin target
|
|
||||||
orbdata = "ignore"
|
|
||||||
orbital = "ignore"
|
|
||||||
orbterm = "ignore"
|
|
||||||
orbutils = "ignore"
|
|
||||||
cosmic-edit = "ignore"
|
|
||||||
cosmic-files = "ignore"
|
|
||||||
cosmic-icons = "ignore"
|
|
||||||
cosmic-term = "ignore"
|
|
||||||
|
|
||||||
# ext4 filesystem support
|
|
||||||
ext4d = {}
|
|
||||||
|
|
||||||
# Firmware loading + Wi-Fi control plane
|
|
||||||
redbear-firmware = {}
|
|
||||||
firmware-loader = {}
|
|
||||||
redbear-wifictl = {}
|
|
||||||
|
|
||||||
# Input layer
|
|
||||||
evdevd = {}
|
|
||||||
udev-shim = {}
|
|
||||||
|
|
||||||
# D-Bus (session + system bus)
|
|
||||||
dbus = {}
|
|
||||||
redbear-sessiond = {}
|
|
||||||
redbear-dbus-services = {}
|
|
||||||
redbear-notifications = {}
|
|
||||||
redbear-upower = {}
|
|
||||||
redbear-udisks = {}
|
|
||||||
redbear-polkit = {}
|
|
||||||
|
|
||||||
# Diagnostic/runtime tooling
|
|
||||||
redbear-info = {}
|
|
||||||
redbear-hwutils = {}
|
|
||||||
redbear-netctl = {}
|
|
||||||
redbear-netctl-console = {}
|
|
||||||
redbear-netstat = {}
|
|
||||||
redbear-traceroute = {}
|
|
||||||
redbear-mtr = {}
|
|
||||||
redbear-nmap = {}
|
|
||||||
cub = {}
|
|
||||||
|
|
||||||
# Wayland protocol
|
|
||||||
libwayland = {}
|
|
||||||
wayland-protocols = {}
|
|
||||||
|
|
||||||
# Input
|
|
||||||
libxkbcommon = {}
|
|
||||||
libevdev = {}
|
|
||||||
libinput = {}
|
|
||||||
|
|
||||||
# Seat management
|
|
||||||
seatd = {}
|
|
||||||
|
|
||||||
# Qt6 stack
|
|
||||||
qtbase = {}
|
|
||||||
qtdeclarative = {}
|
|
||||||
qtsvg = {}
|
|
||||||
qtwayland = {}
|
|
||||||
|
|
||||||
# KF6 Frameworks — Tier 1 (no special deps)
|
|
||||||
kf6-extra-cmake-modules = {}
|
|
||||||
kf6-kcoreaddons = {}
|
|
||||||
kf6-kconfig = {}
|
|
||||||
kf6-ki18n = {}
|
|
||||||
kf6-kcolorscheme = {}
|
|
||||||
kf6-kauth = {}
|
|
||||||
|
|
||||||
# KF6 Frameworks — KWin session-surface chain
|
|
||||||
kf6-kwindowsystem = {}
|
|
||||||
kf6-knotifications = {}
|
|
||||||
kf6-kconfigwidgets = {}
|
|
||||||
kf6-kcrash = {}
|
|
||||||
kf6-kdbusaddons = {}
|
|
||||||
kf6-kglobalaccel = {}
|
|
||||||
kf6-kservice = {}
|
|
||||||
kf6-kpackage = {}
|
|
||||||
kf6-kiconthemes = {}
|
|
||||||
kirigami = {}
|
|
||||||
kf6-kio = {}
|
|
||||||
kf6-kdeclarative = {}
|
|
||||||
kf6-kcmutils = {}
|
|
||||||
kf6-kwayland = {}
|
|
||||||
kdecoration = {}
|
|
||||||
|
|
||||||
# KDE session surface (v2.0 Phases 3–4)
|
|
||||||
kwin = {}
|
|
||||||
|
|
||||||
# Graphics
|
|
||||||
redox-drm = {}
|
|
||||||
mesa = {}
|
|
||||||
libdrm = {}
|
|
||||||
|
|
||||||
# Firmware directory for AMD/Intel GPU blobs
|
|
||||||
[[files]]
|
|
||||||
path = "/lib/firmware/amdgpu"
|
|
||||||
data = ""
|
|
||||||
directory = true
|
|
||||||
mode = 0o755
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/lib/init.d/12_dbus.service"
|
|
||||||
data = """
|
|
||||||
[unit]
|
|
||||||
description = "D-Bus system bus"
|
|
||||||
requires_weak = [
|
|
||||||
"00_base.target",
|
|
||||||
]
|
|
||||||
|
|
||||||
[service]
|
|
||||||
cmd = "ion"
|
|
||||||
args = [
|
|
||||||
"-c",
|
|
||||||
"mkdir -p /var/lib/dbus /run/dbus; rm -f /run/dbus/pid; dbus-uuidgen --ensure; dbus-daemon --system",
|
|
||||||
]
|
|
||||||
type = "oneshot_async"
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/var/lib/dbus"
|
|
||||||
data = ""
|
|
||||||
directory = true
|
|
||||||
mode = 0o755
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/run/dbus"
|
|
||||||
data = ""
|
|
||||||
directory = true
|
|
||||||
mode = 0o755
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/lib/init.d/13_seatd.service"
|
|
||||||
data = """
|
|
||||||
[unit]
|
|
||||||
description = "seatd seat management daemon"
|
|
||||||
requires_weak = [
|
|
||||||
"12_dbus.service",
|
|
||||||
"13_redbear-sessiond.service",
|
|
||||||
]
|
|
||||||
|
|
||||||
[service]
|
|
||||||
cmd = "seatd"
|
|
||||||
args = ["-l", "info"]
|
|
||||||
type = "oneshot_async"
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/lib/init.d/13_redbear-sessiond.service"
|
|
||||||
data = """
|
|
||||||
[unit]
|
|
||||||
description = "Red Bear session broker (org.freedesktop.login1)"
|
|
||||||
requires_weak = [
|
|
||||||
"12_dbus.service",
|
|
||||||
]
|
|
||||||
|
|
||||||
[service]
|
|
||||||
cmd = "ion"
|
|
||||||
args = [
|
|
||||||
"-c",
|
|
||||||
"redbear-sessiond",
|
|
||||||
]
|
|
||||||
type = "oneshot_async"
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/lib/init.d/14_redbear-upower.service"
|
|
||||||
data = """
|
|
||||||
[unit]
|
|
||||||
description = "UPower D-Bus service (org.freedesktop.UPower)"
|
|
||||||
requires_weak = [
|
|
||||||
"12_dbus.service",
|
|
||||||
]
|
|
||||||
|
|
||||||
[service]
|
|
||||||
cmd = "ion"
|
|
||||||
args = [
|
|
||||||
"-c",
|
|
||||||
"redbear-upower",
|
|
||||||
]
|
|
||||||
type = "oneshot_async"
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/lib/init.d/14_redbear-udisks.service"
|
|
||||||
data = """
|
|
||||||
[unit]
|
|
||||||
description = "UDisks2 D-Bus service (org.freedesktop.UDisks2)"
|
|
||||||
requires_weak = [
|
|
||||||
"12_dbus.service",
|
|
||||||
]
|
|
||||||
|
|
||||||
[service]
|
|
||||||
cmd = "ion"
|
|
||||||
args = [
|
|
||||||
"-c",
|
|
||||||
"redbear-udisks",
|
|
||||||
]
|
|
||||||
type = "oneshot_async"
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/lib/init.d/14_redbear-polkit.service"
|
|
||||||
data = """
|
|
||||||
[unit]
|
|
||||||
description = "PolicyKit1 D-Bus service (org.freedesktop.PolicyKit1)"
|
|
||||||
requires_weak = [
|
|
||||||
"12_dbus.service",
|
|
||||||
]
|
|
||||||
|
|
||||||
[service]
|
|
||||||
cmd = "ion"
|
|
||||||
args = [
|
|
||||||
"-c",
|
|
||||||
"redbear-polkit",
|
|
||||||
]
|
|
||||||
type = "oneshot_async"
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/lib/init.d/20_display.service"
|
|
||||||
data = """
|
|
||||||
[unit]
|
|
||||||
description = "Display session service (KDE session)"
|
|
||||||
requires_weak = [
|
|
||||||
"12_dbus.service",
|
|
||||||
"13_redbear-sessiond.service",
|
|
||||||
"13_seatd.service",
|
|
||||||
]
|
|
||||||
|
|
||||||
[service]
|
|
||||||
cmd = "/usr/bin/redbear-kde-session"
|
|
||||||
envs = { VT = "3" }
|
|
||||||
type = "oneshot_async"
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/lib/init.d/30_console.service"
|
|
||||||
data = """
|
|
||||||
[unit]
|
|
||||||
description = "Console terminals"
|
|
||||||
requires_weak = [
|
|
||||||
"29_activate_console.service",
|
|
||||||
]
|
|
||||||
|
|
||||||
[service]
|
|
||||||
cmd = "getty"
|
|
||||||
args = ["2"]
|
|
||||||
type = "oneshot_async"
|
|
||||||
respawn = true
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/lib/init.d/29_activate_console.service"
|
|
||||||
data = """
|
|
||||||
[unit]
|
|
||||||
description = "Activate display VT"
|
|
||||||
requires_weak = [
|
|
||||||
"20_display.service",
|
|
||||||
]
|
|
||||||
|
|
||||||
[service]
|
|
||||||
cmd = "inputd"
|
|
||||||
args = ["-A", "3"]
|
|
||||||
type = "oneshot_async"
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/lib/init.d/31_debug_console.service"
|
|
||||||
data = """
|
|
||||||
[unit]
|
|
||||||
description = "Debug console"
|
|
||||||
requires_weak = [
|
|
||||||
"29_activate_console.service",
|
|
||||||
]
|
|
||||||
|
|
||||||
[service]
|
|
||||||
cmd = "getty"
|
|
||||||
args = ["/scheme/debug/no-preserve", "-J"]
|
|
||||||
type = "oneshot_async"
|
|
||||||
respawn = true
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/bin/redbear-kde-session"
|
|
||||||
mode = 0o755
|
|
||||||
data = """
|
|
||||||
#!/usr/bin/sh
|
|
||||||
|
|
||||||
export DISPLAY=""
|
|
||||||
export HOME="${HOME:-/home/root}"
|
|
||||||
export USER="${USER:-root}"
|
|
||||||
export LOGNAME="${LOGNAME:-$USER}"
|
|
||||||
export WAYLAND_DISPLAY="${WAYLAND_DISPLAY:-wayland-0}"
|
|
||||||
export XDG_SESSION_TYPE=wayland
|
|
||||||
export KDE_FULL_SESSION=true
|
|
||||||
export XDG_CURRENT_DESKTOP=KDE
|
|
||||||
export LIBSEAT_BACKEND=seatd
|
|
||||||
export SEATD_SOCK=/run/seatd.sock
|
|
||||||
export QT_PLUGIN_PATH="${QT_PLUGIN_PATH:-/usr/plugins}"
|
|
||||||
export QT_QPA_PLATFORM_PLUGIN_PATH="${QT_QPA_PLATFORM_PLUGIN_PATH:-/usr/plugins/platforms}"
|
|
||||||
export QML2_IMPORT_PATH="${QML2_IMPORT_PATH:-/usr/qml}"
|
|
||||||
export XCURSOR_THEME="${XCURSOR_THEME:-Pop}"
|
|
||||||
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
|
|
||||||
|
|
||||||
wait_for_path() {
|
|
||||||
target="$1"
|
|
||||||
attempts=0
|
|
||||||
while [ "$attempts" -lt 30 ]; do
|
|
||||||
if [ -e "$target" ]; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
attempts=$((attempts + 1))
|
|
||||||
sleep 1
|
|
||||||
done
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if ! wait_for_path /run/dbus/system_bus_socket; then
|
|
||||||
echo "system D-Bus socket did not appear" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
sleep 2
|
|
||||||
|
|
||||||
if [ -z "${DBUS_SESSION_BUS_ADDRESS:-}" ]; then
|
|
||||||
eval "$(dbus-launch --sh-syntax)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
dbus-update-activation-environment \
|
|
||||||
DBUS_SESSION_BUS_ADDRESS \
|
|
||||||
DBUS_SESSION_BUS_PID \
|
|
||||||
WAYLAND_DISPLAY \
|
|
||||||
XDG_SESSION_ID \
|
|
||||||
XDG_SEAT \
|
|
||||||
XDG_SESSION_TYPE \
|
|
||||||
XDG_RUNTIME_DIR \
|
|
||||||
XDG_CURRENT_DESKTOP \
|
|
||||||
KDE_FULL_SESSION \
|
|
||||||
DISPLAY \
|
|
||||||
HOME \
|
|
||||||
USER
|
|
||||||
|
|
||||||
if [ -z "${KWIN_DRM_DEVICES:-}" ] && [ -e /scheme/drm/card0 ]; then
|
|
||||||
export KWIN_DRM_DEVICES=/scheme/drm/card0
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec kwin_wayland_wrapper --drm
|
|
||||||
"""
|
|
||||||
@@ -23,8 +23,6 @@ data = """
|
|||||||
# clear and recreate tmpdir with 0o1777 permission
|
# clear and recreate tmpdir with 0o1777 permission
|
||||||
rm -rf /tmp
|
rm -rf /tmp
|
||||||
mkdir -m a=rwxt /tmp
|
mkdir -m a=rwxt /tmp
|
||||||
|
|
||||||
nowait sudo --daemon
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
[[files]]
|
[[files]]
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
# Red Bear OS Live Full Configuration with GRUB Boot Manager
|
|
||||||
# Legacy compatibility alias for the canonical GRUB full live target.
|
|
||||||
#
|
|
||||||
# Preferred build: make live CONFIG_NAME=redbear-grub-live-full
|
|
||||||
# Legacy build: make live CONFIG_NAME=redbear-live-full-grub
|
|
||||||
|
|
||||||
include = ["redbear-grub-live-full.toml"]
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# Red Bear OS Live Full Configuration
|
|
||||||
# Legacy compatibility alias for the canonical full live target.
|
|
||||||
#
|
|
||||||
# Preferred build: make live CONFIG_NAME=redbear-live
|
|
||||||
# Legacy build: make live CONFIG_NAME=redbear-live-full
|
|
||||||
|
|
||||||
include = ["redbear-live.toml"]
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# Red Bear OS Live Mini Configuration with GRUB Boot Manager
|
|
||||||
# Legacy compatibility alias for the canonical GRUB mini live target.
|
|
||||||
#
|
|
||||||
# Preferred build: make live CONFIG_NAME=redbear-grub-live-mini
|
|
||||||
# Legacy build: make live CONFIG_NAME=redbear-live-mini-grub
|
|
||||||
|
|
||||||
include = ["redbear-grub-live-mini.toml"]
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
# Red Bear OS Live Minimal Configuration with GRUB Boot Manager
|
|
||||||
# Live ISO for minimal console target with installer-native GRUB chainload.
|
|
||||||
#
|
|
||||||
# Build: make live CONFIG_NAME=redbear-live-minimal-grub
|
|
||||||
|
|
||||||
include = ["redbear-live-minimal.toml", "redbear-grub.toml"]
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
# Red Bear OS Live Minimal Configuration
|
|
||||||
# Live ISO variant for the minimal console/server target.
|
|
||||||
#
|
|
||||||
# Build: make live CONFIG_NAME=redbear-live-minimal
|
|
||||||
|
|
||||||
include = ["redbear-minimal.toml"]
|
|
||||||
|
|
||||||
[general]
|
|
||||||
filesystem_size = 3072
|
|
||||||
|
|
||||||
[packages]
|
|
||||||
cub = {}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# Red Bear OS Live Configuration
|
|
||||||
# Canonical full live ISO target for the desktop/session surface on real bare metal.
|
|
||||||
#
|
|
||||||
# Build: make live CONFIG_NAME=redbear-live
|
|
||||||
# This ISO is for real bare-metal boot/install/recovery, not VM/QEMU use.
|
|
||||||
|
|
||||||
include = ["redbear-full.toml"]
|
|
||||||
|
|
||||||
[general]
|
|
||||||
filesystem_size = 3072
|
|
||||||
efi_partition_size = 1
|
|
||||||
|
|
||||||
[packages]
|
|
||||||
cub = {}
|
|
||||||
redbear-meta = {}
|
|
||||||
@@ -1,19 +1,26 @@
|
|||||||
# Red Bear OS Live Mini Configuration
|
# Red Bear OS Mini Configuration
|
||||||
# Live ISO variant for console/recovery/install on bare metal.
|
# Text-only ISO for console/recovery/install on bare metal.
|
||||||
#
|
#
|
||||||
# Build: make live CONFIG_NAME=redbear-live-mini
|
# Build: make live CONFIG_NAME=redbear-mini
|
||||||
#
|
#
|
||||||
# Target contract:
|
# Target contract:
|
||||||
# - keep a text-login live/recovery surface only
|
# - text-login live/recovery/install surface
|
||||||
# - use boot framebuffer for VT text consoles via vesad + fbcond
|
# - boot framebuffer for VT text consoles via vesad + fbcond
|
||||||
# - ship all non-graphics, non-firmware packages from the full profile
|
# - all non-graphics, non-firmware packages from the full profile
|
||||||
# - ship no linux-firmware payload, no firmware-loader, no GPU/display drivers
|
# - no linux-firmware payload, no firmware-loader, no GPU/display drivers
|
||||||
|
|
||||||
include = ["minimal.toml", "redbear-legacy-base.toml", "redbear-netctl.toml"]
|
include = ["minimal.toml", "redbear-legacy-base.toml", "redbear-netctl.toml"]
|
||||||
|
|
||||||
[general]
|
[general]
|
||||||
filesystem_size = 1536
|
filesystem_size = 1536
|
||||||
|
|
||||||
|
[users.messagebus]
|
||||||
|
uid = 100
|
||||||
|
gid = 100
|
||||||
|
name = "messagebus"
|
||||||
|
home = "/nonexistent"
|
||||||
|
shell = "/usr/bin/ion"
|
||||||
|
|
||||||
[packages]
|
[packages]
|
||||||
# Red Bear OS branding and host utilities.
|
# Red Bear OS branding and host utilities.
|
||||||
redbear-release = {}
|
redbear-release = {}
|
||||||
@@ -188,11 +195,25 @@ cmd = "i2cd"
|
|||||||
type = "oneshot_async"
|
type = "oneshot_async"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
[[files]]
|
||||||
|
path = "/etc/init.d/00_i2c-dw-acpi.service"
|
||||||
|
data = """
|
||||||
|
[unit]
|
||||||
|
description = "DesignWare ACPI I2C controller (non-blocking)"
|
||||||
|
requires_weak = [
|
||||||
|
"00_i2cd.service",
|
||||||
|
]
|
||||||
|
|
||||||
|
[service]
|
||||||
|
cmd = "dw-acpi-i2cd"
|
||||||
|
type = "oneshot_async"
|
||||||
|
"""
|
||||||
|
|
||||||
[[files]]
|
[[files]]
|
||||||
path = "/etc/init.d/00_intel-gpiod.service"
|
path = "/etc/init.d/00_intel-gpiod.service"
|
||||||
data = """
|
data = """
|
||||||
[unit]
|
[unit]
|
||||||
description = "Intel ACPI GPIO registrar (non-blocking on live-mini)"
|
description = "Intel ACPI GPIO registrar (non-blocking)"
|
||||||
requires_weak = [
|
requires_weak = [
|
||||||
"00_gpiod.service",
|
"00_gpiod.service",
|
||||||
"00_i2cd.service",
|
"00_i2cd.service",
|
||||||
@@ -222,7 +243,7 @@ type = "oneshot_async"
|
|||||||
path = "/etc/init.d/00_i2c-hidd.service"
|
path = "/etc/init.d/00_i2c-hidd.service"
|
||||||
data = """
|
data = """
|
||||||
[unit]
|
[unit]
|
||||||
description = "ACPI I2C HID bring-up daemon (non-blocking on live-mini)"
|
description = "ACPI I2C HID bring-up daemon (non-blocking)"
|
||||||
requires_weak = [
|
requires_weak = [
|
||||||
"00_i2cd.service",
|
"00_i2cd.service",
|
||||||
"00_i2c-dw-acpi.service",
|
"00_i2c-dw-acpi.service",
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
# Red Bear OS Minimal Configuration with GRUB Boot Manager
|
|
||||||
# Minimal console/server target with installer-native GRUB chainload.
|
|
||||||
#
|
|
||||||
# Build: make all CONFIG_NAME=redbear-minimal-grub
|
|
||||||
|
|
||||||
include = ["redbear-minimal.toml", "redbear-grub.toml"]
|
|
||||||
@@ -1,219 +0,0 @@
|
|||||||
# Red Bear OS Minimal Configuration
|
|
||||||
# Console/Server variant with bare-metal driver support but no GUI.
|
|
||||||
# Includes all non-graphics, non-firmware packages from the full profile.
|
|
||||||
#
|
|
||||||
# Build: make all CONFIG_NAME=redbear-minimal
|
|
||||||
|
|
||||||
include = ["minimal.toml", "redbear-legacy-base.toml", "redbear-device-services.toml", "redbear-netctl.toml"]
|
|
||||||
|
|
||||||
[general]
|
|
||||||
# Minimal image carries the full non-graphics package set;
|
|
||||||
# 2048 MiB accommodates CLI tools, D-Bus services, and filesystem utilities.
|
|
||||||
filesystem_size = 2048
|
|
||||||
|
|
||||||
[packages]
|
|
||||||
# Red Bear OS branding
|
|
||||||
redbear-release = {}
|
|
||||||
|
|
||||||
# Native Redox PCI/USB listing tools (lspci, lsusb)
|
|
||||||
redbear-hwutils = {}
|
|
||||||
|
|
||||||
# Redox-native netctl compatibility command
|
|
||||||
redbear-netctl = {}
|
|
||||||
redbear-netctl-console = {}
|
|
||||||
|
|
||||||
# Native network reporting and connect-scan tools
|
|
||||||
redbear-netstat = {}
|
|
||||||
redbear-traceroute = {}
|
|
||||||
redbear-mtr = {}
|
|
||||||
redbear-nmap = {}
|
|
||||||
|
|
||||||
# Wi-Fi control plane (firmware-loader comes from redbear-device-services.toml)
|
|
||||||
firmware-loader = {}
|
|
||||||
redbear-wifictl = {}
|
|
||||||
|
|
||||||
# Input/runtime service prerequisites
|
|
||||||
evdevd = {}
|
|
||||||
udev-shim = {}
|
|
||||||
|
|
||||||
# Terminal file manager
|
|
||||||
mc = {}
|
|
||||||
|
|
||||||
# Diagnostic tool
|
|
||||||
redbear-info = {}
|
|
||||||
|
|
||||||
# Package builder (cub -S/-B/-G CLI)
|
|
||||||
cub = {}
|
|
||||||
|
|
||||||
# ── D-Bus IPC and session services ──
|
|
||||||
dbus = {}
|
|
||||||
redbear-sessiond = {}
|
|
||||||
redbear-dbus-services = {}
|
|
||||||
redbear-notifications = {}
|
|
||||||
redbear-upower = {}
|
|
||||||
redbear-udisks = {}
|
|
||||||
redbear-polkit = {}
|
|
||||||
|
|
||||||
# ── IOMMU DMA remapping ──
|
|
||||||
iommu = {}
|
|
||||||
|
|
||||||
# ── Standard CLI tools (from server profile) ──
|
|
||||||
bash = {}
|
|
||||||
bottom = {}
|
|
||||||
curl = {}
|
|
||||||
diffutils = {}
|
|
||||||
findutils = {}
|
|
||||||
git = {}
|
|
||||||
htop = {}
|
|
||||||
|
|
||||||
# ── Filesystem support ──
|
|
||||||
ext4d = {}
|
|
||||||
redoxfs = {}
|
|
||||||
|
|
||||||
# ── System installer ──
|
|
||||||
installer = {}
|
|
||||||
|
|
||||||
# ── Build / packaging utilities ──
|
|
||||||
patchelf = {}
|
|
||||||
shared-mime-info = {}
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/etc/netctl/active"
|
|
||||||
data = "wired-dhcp\n"
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/etc/issue"
|
|
||||||
data = """
|
|
||||||
########## Red Bear OS #########
|
|
||||||
# Login with the following: #
|
|
||||||
# `user` #
|
|
||||||
# `root`:`password` #
|
|
||||||
################################
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/etc/motd"
|
|
||||||
data = """
|
|
||||||
Red Bear OS v0.1.0 "Denali" — Built on Redox OS
|
|
||||||
Type 'help' for available commands.
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/lib/init.d/12_dbus.service"
|
|
||||||
data = """
|
|
||||||
[unit]
|
|
||||||
description = "D-Bus system bus"
|
|
||||||
requires_weak = [
|
|
||||||
"12_boot-late.target",
|
|
||||||
]
|
|
||||||
|
|
||||||
[service]
|
|
||||||
cmd = "ion"
|
|
||||||
args = [
|
|
||||||
"-c",
|
|
||||||
"mkdir -p /var/lib/dbus /run/dbus; rm -f /run/dbus/pid; dbus-uuidgen --ensure; dbus-daemon --system",
|
|
||||||
]
|
|
||||||
type = "oneshot_async"
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/lib/init.d/13_redbear-sessiond.service"
|
|
||||||
data = """
|
|
||||||
[unit]
|
|
||||||
description = "Red Bear session broker (org.freedesktop.login1)"
|
|
||||||
requires_weak = [
|
|
||||||
"12_dbus.service",
|
|
||||||
]
|
|
||||||
|
|
||||||
[service]
|
|
||||||
cmd = "ion"
|
|
||||||
args = [
|
|
||||||
"-c",
|
|
||||||
"redbear-sessiond",
|
|
||||||
]
|
|
||||||
type = "oneshot_async"
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/lib/init.d/13_iommu.service"
|
|
||||||
data = """
|
|
||||||
[unit]
|
|
||||||
description = "IOMMU DMA remapping daemon"
|
|
||||||
requires_weak = [
|
|
||||||
"12_boot-late.target",
|
|
||||||
"00_pcid-spawner.service",
|
|
||||||
]
|
|
||||||
|
|
||||||
[service]
|
|
||||||
cmd = "/usr/bin/iommu"
|
|
||||||
type = "oneshot_async"
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/lib/init.d/14_redbear-upower.service"
|
|
||||||
data = """
|
|
||||||
[unit]
|
|
||||||
description = "UPower D-Bus service (org.freedesktop.UPower)"
|
|
||||||
requires_weak = [
|
|
||||||
"12_dbus.service",
|
|
||||||
]
|
|
||||||
|
|
||||||
[service]
|
|
||||||
cmd = "ion"
|
|
||||||
args = [
|
|
||||||
"-c",
|
|
||||||
"redbear-upower",
|
|
||||||
]
|
|
||||||
type = "oneshot_async"
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/lib/init.d/14_redbear-udisks.service"
|
|
||||||
data = """
|
|
||||||
[unit]
|
|
||||||
description = "UDisks2 D-Bus service (org.freedesktop.UDisks2)"
|
|
||||||
requires_weak = [
|
|
||||||
"12_dbus.service",
|
|
||||||
]
|
|
||||||
|
|
||||||
[service]
|
|
||||||
cmd = "ion"
|
|
||||||
args = [
|
|
||||||
"-c",
|
|
||||||
"redbear-udisks",
|
|
||||||
]
|
|
||||||
type = "oneshot_async"
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/usr/lib/init.d/14_redbear-polkit.service"
|
|
||||||
data = """
|
|
||||||
[unit]
|
|
||||||
description = "PolicyKit1 D-Bus service (org.freedesktop.PolicyKit1)"
|
|
||||||
requires_weak = [
|
|
||||||
"12_dbus.service",
|
|
||||||
]
|
|
||||||
|
|
||||||
[service]
|
|
||||||
cmd = "ion"
|
|
||||||
args = [
|
|
||||||
"-c",
|
|
||||||
"redbear-polkit",
|
|
||||||
]
|
|
||||||
type = "oneshot_async"
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/var/lib/dbus"
|
|
||||||
data = ""
|
|
||||||
directory = true
|
|
||||||
mode = 0o755
|
|
||||||
|
|
||||||
[[files]]
|
|
||||||
path = "/run/dbus"
|
|
||||||
data = ""
|
|
||||||
directory = true
|
|
||||||
mode = 0o755
|
|
||||||
|
|
||||||
# VT/getty/login chain: initfs starts inputd + vesad + fbcond in phase 1,
|
|
||||||
# then minimal.toml legacy 30_console runs inputd -A 2 + getty 2 + getty debug.
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
# Red Bear OS Wayland Validation Profile
|
|
||||||
#
|
|
||||||
# Build: ./local/scripts/build-redbear.sh redbear-wayland
|
|
||||||
# Phase 1 substrate validation: ./local/scripts/test-phase1-desktop-substrate.sh --qemu redbear-wayland
|
|
||||||
# Phase 2 Wayland validation: ./local/scripts/test-phase4-wayland-qemu.sh
|
|
||||||
#
|
|
||||||
# Validation-only profile:
|
|
||||||
# - the packaged compositor/runtime harness remains bounded
|
|
||||||
# - this profile remains the bounded validation slice beneath redbear-kde -> kwin_wayland
|
|
||||||
|
|
||||||
include = ["wayland.toml"]
|
|
||||||
|
|
||||||
[packages]
|
|
||||||
redbear-firmware = {}
|
|
||||||
redox-drm = {}
|
|
||||||
qt6-wayland-smoke = {}
|
|
||||||
@@ -105,7 +105,7 @@ echo 'PODMAN_BUILD?=0' > .config
|
|||||||
|
|
||||||
### Select Build Configuration
|
### Select Build Configuration
|
||||||
|
|
||||||
Tracked Red Bear work should normally be built and validated through the four supported
|
Tracked Red Bear work should normally be built and validated through the three supported
|
||||||
`redbear-*` compile targets. For desktop work specifically, `redbear-full` is the tracked
|
`redbear-*` compile targets. For desktop work specifically, `redbear-full` is the tracked
|
||||||
desktop-capable target.
|
desktop-capable target.
|
||||||
|
|
||||||
@@ -144,20 +144,19 @@ For the full layout and rationale, see `local/docs/EXTERNAL-TOOLCHAIN.md`.
|
|||||||
```bash
|
```bash
|
||||||
# Preferred Red Bear wrapper:
|
# Preferred Red Bear wrapper:
|
||||||
./local/scripts/build-redbear.sh redbear-mini
|
./local/scripts/build-redbear.sh redbear-mini
|
||||||
./local/scripts/build-redbear.sh redbear-live-mini
|
|
||||||
./local/scripts/build-redbear.sh redbear-full
|
./local/scripts/build-redbear.sh redbear-full
|
||||||
./local/scripts/build-redbear.sh redbear-live-full
|
./local/scripts/build-redbear.sh redbear-grub
|
||||||
|
|
||||||
# Direct make is still valid when needed:
|
# Direct make is still valid when needed:
|
||||||
make all CONFIG_NAME=redbear-full
|
make all CONFIG_NAME=redbear-full
|
||||||
```
|
```
|
||||||
|
|
||||||
For tracked Red Bear work, prefer these four compile targets over older historical names.
|
For tracked Red Bear work, prefer these three compile targets over older historical names.
|
||||||
|
|
||||||
### Build a Live ISO
|
### Build a Live ISO
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
make live CONFIG_NAME=redbear-live-full
|
make live CONFIG_NAME=redbear-full
|
||||||
# Produces: build/x86_64/redbear-live.iso
|
# Produces: build/x86_64/redbear-live.iso
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -93,14 +93,13 @@ That means:
|
|||||||
The tracked Red Bear compile targets are:
|
The tracked Red Bear compile targets are:
|
||||||
|
|
||||||
- `redbear-mini`
|
- `redbear-mini`
|
||||||
- `redbear-live-mini`
|
|
||||||
- `redbear-full`
|
- `redbear-full`
|
||||||
- `redbear-live-full`
|
- `redbear-grub`
|
||||||
|
|
||||||
These are the only supported compile targets. Older names such as `redbear-minimal`,
|
These are the only supported compile targets. Older names such as `redbear-minimal`,
|
||||||
`redbear-desktop`, `redbear-wayland`, `redbear-kde`, and `redbear-live` may still appear in
|
`redbear-desktop`, `redbear-wayland`, `redbear-kde`, `redbear-live`, `redbear-live-mini`,
|
||||||
historical notes or legacy implementation details, but they are not the current compile-target
|
and `redbear-live-full` may still appear in historical notes or legacy implementation details,
|
||||||
surface.
|
but they are not the current compile-target surface.
|
||||||
|
|
||||||
### `redbear-mini`
|
### `redbear-mini`
|
||||||
|
|
||||||
@@ -125,31 +124,20 @@ Scope:
|
|||||||
- Qt base integration,
|
- Qt base integration,
|
||||||
- the active desktop-capable target surface.
|
- the active desktop-capable target surface.
|
||||||
|
|
||||||
### `redbear-live-mini`
|
### `redbear-grub`
|
||||||
|
|
||||||
Live/demo/recovery form of the mini baseline for real bare metal.
|
Text-only console/recovery target with GRUB boot manager for real bare metal.
|
||||||
|
|
||||||
Scope:
|
Scope:
|
||||||
|
|
||||||
- diagnostics,
|
- diagnostics,
|
||||||
- recovery workflows,
|
- recovery workflows,
|
||||||
- installability for the non-graphics target.
|
- multi-boot bare-metal install with GRUB chainload.
|
||||||
|
|
||||||
### `redbear-live-full`
|
|
||||||
|
|
||||||
Live/demo/recovery form of the full desktop target for real bare metal.
|
|
||||||
|
|
||||||
Scope:
|
|
||||||
|
|
||||||
- diagnostics,
|
|
||||||
- recovery workflows,
|
|
||||||
- installability,
|
|
||||||
- live desktop-capable system identity.
|
|
||||||
|
|
||||||
### Desktop policy
|
### Desktop policy
|
||||||
|
|
||||||
- Desktop/graphics are available only on `redbear-full` and `redbear-live-full`.
|
- Desktop/graphics are available only on `redbear-full`.
|
||||||
- Validation work that does not require graphics should prefer `redbear-mini` or `redbear-live-mini`.
|
- Validation work that does not require graphics should prefer `redbear-mini` or `redbear-grub`.
|
||||||
- Live `.iso` outputs are for real bare-metal boot/install workflows, not for VM/QEMU execution; virtualization should use the `harddrive.img`-based target surface.
|
- Live `.iso` outputs are for real bare-metal boot/install workflows, not for VM/QEMU execution; virtualization should use the `harddrive.img`-based target surface.
|
||||||
|
|
||||||
## Current State Baseline
|
## Current State Baseline
|
||||||
@@ -384,9 +372,9 @@ Canonical references:
|
|||||||
|
|
||||||
Acceptance:
|
Acceptance:
|
||||||
|
|
||||||
- `redbear-wayland` remains the narrow runtime validation slice,
|
- `redbear-full` remains the broader desktop/session plumbing slice (the Wayland validation slice
|
||||||
- `redbear-full` remains the broader desktop/session plumbing slice,
|
is handled within `redbear-full`),
|
||||||
- the active desktop-capable tracked targets keep honest session-viability language tied to `redbear-full` / `redbear-live-full`, not older historical target names.
|
- the active desktop-capable tracked targets keep honest session-viability language tied to `redbear-full`, not older historical target names.
|
||||||
|
|
||||||
### 8. Hardware validation and support labeling
|
### 8. Hardware validation and support labeling
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -107,8 +107,8 @@ This summary is only a quick orientation layer. For canonical current-state deta
|
|||||||
- `local/docs/PROFILE-MATRIX.md` for support-language by tracked profile,
|
- `local/docs/PROFILE-MATRIX.md` for support-language by tracked profile,
|
||||||
- and the active subsystem plans under `local/docs/` for detailed current workstreams.
|
- and the active subsystem plans under `local/docs/` for detailed current workstreams.
|
||||||
|
|
||||||
- **Compile targets**: the supported compile targets are `redbear-mini`, `redbear-live-mini`, `redbear-full`, and `redbear-live-full`
|
- **Compile targets**: the supported compile targets are `redbear-mini`, `redbear-full`, and `redbear-grub`
|
||||||
- **Live ISO policy**: live `.iso` outputs (`redbear-live-mini`, `redbear-live-full`) are for real bare-metal boot/install/recovery workflows, not the VM/QEMU execution surface.
|
- **Live ISO policy**: live `.iso` outputs (`make live`) are for real bare-metal boot/install/recovery workflows, not the VM/QEMU execution surface.
|
||||||
- **Wayland**: libwayland + wayland-protocols built. A bounded greeter/compositor-backed login proof now passes, but broader compositor/runtime stability remains incomplete.
|
- **Wayland**: libwayland + wayland-protocols built. A bounded greeter/compositor-backed login proof now passes, but broader compositor/runtime stability remains incomplete.
|
||||||
- **Qt6**: qtbase 6.11.0 (Core+Gui+Widgets+DBus+Wayland), qtdeclarative, qtsvg, qtwayland ALL BUILT
|
- **Qt6**: qtbase 6.11.0 (Core+Gui+Widgets+DBus+Wayland), qtdeclarative, qtsvg, qtwayland ALL BUILT
|
||||||
- **D-Bus**: 1.16.2 built for Redox. Qt6DBus enabled.
|
- **D-Bus**: 1.16.2 built for Redox. Qt6DBus enabled.
|
||||||
@@ -120,7 +120,7 @@ This summary is only a quick orientation layer. For canonical current-state deta
|
|||||||
- **PCI / IRQ quality**: architecturally strong substrate exists, with bounded MSI-X, IOMMU, xHCI IRQ, and low-level-controller proof surfaces; broader hardware robustness is still intentionally tracked as open work in `../local/docs/IRQ-AND-LOWLEVEL-CONTROLLERS-ENHANCEMENT-PLAN.md`
|
- **PCI / IRQ quality**: architecturally strong substrate exists, with bounded MSI-X, IOMMU, xHCI IRQ, and low-level-controller proof surfaces; broader hardware robustness is still intentionally tracked as open work in `../local/docs/IRQ-AND-LOWLEVEL-CONTROLLERS-ENHANCEMENT-PLAN.md`
|
||||||
- **Wi-Fi profile target**: `config/redbear-wifi-experimental.toml` is the first explicit tracked image slice for bounded Intel Wi‑Fi validation, instead of spreading that claim across the generic desktop profiles.
|
- **Wi-Fi profile target**: `config/redbear-wifi-experimental.toml` is the first explicit tracked image slice for bounded Intel Wi‑Fi validation, instead of spreading that claim across the generic desktop profiles.
|
||||||
- **Bluetooth**: one bounded in-tree BLE-first experimental slice exists, and the Battery Level read-only workload now has a packaged in-guest checker plus a host QEMU harness; QEMU validation is still in progress, so broad desktop Bluetooth parity is still incomplete
|
- **Bluetooth**: one bounded in-tree BLE-first experimental slice exists, and the Battery Level read-only workload now has a packaged in-guest checker plus a host QEMU harness; QEMU validation is still in progress, so broad desktop Bluetooth parity is still incomplete
|
||||||
- **Desktop direction**: `redbear-full` / `redbear-live-full` carry the desktop-capable target surface; the bounded greeter/login slice now passes, while the wider desktop runtime stack is still incomplete.
|
- **Desktop direction**: `redbear-full` carries the desktop-capable target surface; the bounded greeter/login slice now passes, while the wider desktop runtime stack is still incomplete.
|
||||||
- **ACPI**: materially complete for the historical boot baseline, not release-grade complete; implemented: AML mutex real state, EC widened accesses via byte transactions, kstop-based shutdown eventing, explicit `RSDP_ADDR` forwarding into `acpid`, x86 BIOS-search AML fallback, and real-but-provisional AML-backed power enumeration. **Known gaps**: the explicit boot-path producer contract for AML bootstrap is still underdocumented, `acpid` startup hardening remains open, shutdown/power reporting are still provisional, sleep state transitions and sleep eventing remain incomplete, DMAR ownership is still transitional, and bare-metal validation is still bounded. See `local/docs/ACPI-IMPROVEMENT-PLAN.md`.
|
- **ACPI**: materially complete for the historical boot baseline, not release-grade complete; implemented: AML mutex real state, EC widened accesses via byte transactions, kstop-based shutdown eventing, explicit `RSDP_ADDR` forwarding into `acpid`, x86 BIOS-search AML fallback, and real-but-provisional AML-backed power enumeration. **Known gaps**: the explicit boot-path producer contract for AML bootstrap is still underdocumented, `acpid` startup hardening remains open, shutdown/power reporting are still provisional, sleep state transitions and sleep eventing remain incomplete, DMAR ownership is still transitional, and bare-metal validation is still bounded. See `local/docs/ACPI-IMPROVEMENT-PLAN.md`.
|
||||||
- **Linux driver compat**: linux-kpi now includes early wireless-subsystem compatibility scaffolding in addition to the earlier helper layer, redox-driver-sys and firmware-loader compile, and the bounded Intel Wi-Fi path now has host-tested scan/connect/disconnect/profile/reporting flows without claiming real hardware Wi-Fi connectivity.
|
- **Linux driver compat**: linux-kpi now includes early wireless-subsystem compatibility scaffolding in addition to the earlier helper layer, redox-driver-sys and firmware-loader compile, and the bounded Intel Wi-Fi path now has host-tested scan/connect/disconnect/profile/reporting flows without claiming real hardware Wi-Fi connectivity.
|
||||||
- **Wi-Fi validation tooling**: `redbear-phase5-wifi-check` and `redbear-phase5-wifi-capture` are now packaged in-guest helpers for bounded Intel Wi-Fi runtime validation and evidence capture on bare metal or VFIO-backed guests.
|
- **Wi-Fi validation tooling**: `redbear-phase5-wifi-check` and `redbear-phase5-wifi-capture` are now packaged in-guest helpers for bounded Intel Wi-Fi runtime validation and evidence capture on bare metal or VFIO-backed guests.
|
||||||
|
|||||||
+59
-134
@@ -24,7 +24,7 @@ Build flow:
|
|||||||
```
|
```
|
||||||
make all CONFIG_NAME=redbear-full
|
make all CONFIG_NAME=redbear-full
|
||||||
→ mk/config.mk resolves to the active desktop/graphics compile target
|
→ mk/config.mk resolves to the active desktop/graphics compile target
|
||||||
→ Desktop/graphics are available only on redbear-full and redbear-live-full
|
→ Desktop/graphics are available only on redbear-full
|
||||||
→ repo cook builds all packages including our custom ones
|
→ repo cook builds all packages including our custom ones
|
||||||
→ mk/disk.mk creates harddrive.img with Red Bear branding
|
→ mk/disk.mk creates harddrive.img with Red Bear branding
|
||||||
```
|
```
|
||||||
@@ -37,28 +37,14 @@ make all CONFIG_NAME=redbear-full # Rebuild the active desktop/graphics
|
|||||||
|
|
||||||
## ACTIVE COMPILE TARGETS
|
## ACTIVE COMPILE TARGETS
|
||||||
|
|
||||||
The supported compile targets are exactly:
|
The supported compile targets are exactly three. All three work for both `make all` (harddrive.img)
|
||||||
|
and `make live` (ISO):
|
||||||
|
|
||||||
Non-live (harddrive.img for QEMU / development):
|
- `redbear-full` — Desktop/graphics-enabled target (Wayland + KDE + GPU drivers)
|
||||||
- `redbear-full` — Desktop/graphics-enabled target
|
- `redbear-mini` — Text-only console/recovery/install target
|
||||||
- `redbear-full-grub` — Desktop/graphics with GRUB boot manager
|
- `redbear-grub` — Text-only target with GRUB boot manager
|
||||||
|
|
||||||
Live (ISO for real bare metal):
|
Desktop/graphics are available only on `redbear-full`.
|
||||||
- `redbear-live` — Full desktop live ISO (graphical greeter + text fallback)
|
|
||||||
- `redbear-live-mini` — Text-only mini live ISO for recovery/bare metal
|
|
||||||
- `redbear-grub-live-full` — Full desktop live ISO with GRUB boot manager
|
|
||||||
- `redbear-grub-live-mini` — Text-only mini live ISO with GRUB
|
|
||||||
|
|
||||||
Legacy aliases (accepted by build-iso.sh):
|
|
||||||
- `redbear-live-full` → `redbear-live`
|
|
||||||
- `redbear-live-mini-grub` → `redbear-grub-live-mini`
|
|
||||||
- `redbear-live-full-grub` → `redbear-grub-live-full`
|
|
||||||
|
|
||||||
Desktop/graphics are available only on `redbear-full`, `redbear-live`, `redbear-full-grub`, and `redbear-grub-live-full`.
|
|
||||||
|
|
||||||
Names such as `redbear-kde`, `redbear-wayland`, and `redbear-minimal` may still appear in older
|
|
||||||
docs, legacy validation notes, or in-repo staging configs, but they should not be treated as the
|
|
||||||
current supported compile targets.
|
|
||||||
|
|
||||||
## TRACKING UPSTREAM (SYNC WITH REDOX OS)
|
## TRACKING UPSTREAM (SYNC WITH REDOX OS)
|
||||||
|
|
||||||
@@ -176,9 +162,10 @@ redox-master/ ← git pull updates mainline Redox
|
|||||||
├── config/
|
├── config/
|
||||||
│ ├── desktop.toml ← mainline configs (untouched)
|
│ ├── desktop.toml ← mainline configs (untouched)
|
||||||
│ ├── minimal.toml
|
│ ├── minimal.toml
|
||||||
│ ├── redbear-full.toml ← Active desktop/graphics target
|
│ ├── redbear-full.toml ← Desktop/graphics target
|
||||||
│ ├── redbear-live-full.toml ← Live desktop/graphics target
|
│ ├── redbear-mini.toml ← Text-only console/recovery target
|
||||||
│ ├── redbear-mini*.toml ← Minimal target surface (legacy/staging naming may still vary in-tree)
|
│ ├── redbear-grub.toml ← Text-only with GRUB boot manager
|
||||||
|
│ ├── redbear-grub-policy.toml ← GRUB policy fragment (bootloader = "grub", efi_partition_size = 16)
|
||||||
│ └── redbear-greeter-services.toml ← Greeter/auth/session-launch wiring fragment
|
│ └── redbear-greeter-services.toml ← Greeter/auth/session-launch wiring fragment
|
||||||
├── recipes/ ← mainline package recipes (untouched)
|
├── recipes/ ← mainline package recipes (untouched)
|
||||||
├── mk/ ← mainline build system (untouched)
|
├── mk/ ← mainline build system (untouched)
|
||||||
@@ -240,23 +227,25 @@ redox-master/ ← git pull updates mainline Redox
|
|||||||
## HOW TO BUILD RED BEAR OS
|
## HOW TO BUILD RED BEAR OS
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Active desktop/graphics target
|
# Build targets (all three work for both `make all` and `make live`)
|
||||||
./local/scripts/build-redbear.sh redbear-full
|
./local/scripts/build-redbear.sh redbear-full # Desktop/graphics target
|
||||||
|
./local/scripts/build-redbear.sh redbear-mini # Text-only console/recovery target
|
||||||
|
./local/scripts/build-redbear.sh redbear-grub # Text-only with GRUB boot manager
|
||||||
|
|
||||||
# Minimal non-desktop target
|
# Or manually:
|
||||||
./local/scripts/build-redbear.sh redbear-mini
|
make all CONFIG_NAME=redbear-full # Desktop/graphics → harddrive.img
|
||||||
|
make all CONFIG_NAME=redbear-mini # Text-only → harddrive.img
|
||||||
|
make all CONFIG_NAME=redbear-grub # Text-only + GRUB → harddrive.img
|
||||||
|
|
||||||
# Live images
|
# Live ISO (for real bare metal)
|
||||||
./local/scripts/build-redbear.sh redbear-live && make live CONFIG_NAME=redbear-live
|
make live CONFIG_NAME=redbear-full # Full desktop live ISO
|
||||||
./local/scripts/build-redbear.sh redbear-live-mini && make live CONFIG_NAME=redbear-live-mini
|
make live CONFIG_NAME=redbear-mini # Text-only mini live ISO
|
||||||
./local/scripts/build-redbear.sh redbear-live-mini && make live CONFIG_NAME=redbear-grub-live-mini
|
make live CONFIG_NAME=redbear-grub # Text-only mini live ISO with GRUB
|
||||||
./local/scripts/build-redbear.sh redbear-live && make live CONFIG_NAME=redbear-grub-live-full
|
|
||||||
|
|
||||||
# Or using the helper:
|
# Or using the helper:
|
||||||
scripts/build-iso.sh redbear-live
|
scripts/build-iso.sh redbear-full # Full desktop live ISO
|
||||||
scripts/build-iso.sh redbear-live-mini
|
scripts/build-iso.sh redbear-mini # Text-only mini (default)
|
||||||
scripts/build-iso.sh redbear-grub-live-mini
|
scripts/build-iso.sh redbear-grub # Text-only + GRUB
|
||||||
scripts/build-iso.sh redbear-grub-live-full
|
|
||||||
|
|
||||||
# VM-network baseline validation helpers
|
# VM-network baseline validation helpers
|
||||||
./local/scripts/validate-vm-network-baseline.sh
|
./local/scripts/validate-vm-network-baseline.sh
|
||||||
@@ -266,10 +255,9 @@ scripts/build-iso.sh redbear-grub-live-full
|
|||||||
|
|
||||||
# Phase 1 desktop-substrate validation (v2.0 plan: relibc headers, evdevd, udev-shim,
|
# Phase 1 desktop-substrate validation (v2.0 plan: relibc headers, evdevd, udev-shim,
|
||||||
# firmware-loader, DRM/KMS, health-check — covers 6 acceptance areas)
|
# firmware-loader, DRM/KMS, health-check — covers 6 acceptance areas)
|
||||||
./local/scripts/test-phase1-desktop-substrate.sh --qemu redbear-wayland
|
./local/scripts/test-phase1-desktop-substrate.sh --qemu redbear-full
|
||||||
|
|
||||||
# Legacy Phase 3 runtime-substrate validation (historical P0-P6 numbering; script still works)
|
# Legacy Phase 3 runtime-substrate validation (historical P0-P6 numbering; script still works)
|
||||||
# Use the active desktop target when adapting historical validation flows.
|
|
||||||
./local/scripts/test-phase3-runtime-substrate.sh --qemu redbear-full
|
./local/scripts/test-phase3-runtime-substrate.sh --qemu redbear-full
|
||||||
|
|
||||||
# Low-level controller validation
|
# Low-level controller validation
|
||||||
@@ -296,7 +284,7 @@ scripts/build-iso.sh redbear-grub-live-full
|
|||||||
# The aggregate USB wrapper runs xHCI mode, full USB stack, and USB storage readback proofs in sequence.
|
# The aggregate USB wrapper runs xHCI mode, full USB stack, and USB storage readback proofs in sequence.
|
||||||
|
|
||||||
# Legacy Phase 4 Wayland runtime validation (historical P0-P6 numbering; script still works)
|
# Legacy Phase 4 Wayland runtime validation (historical P0-P6 numbering; script still works)
|
||||||
./local/scripts/build-redbear.sh redbear-wayland
|
./local/scripts/build-redbear.sh redbear-full
|
||||||
./local/scripts/test-phase4-wayland-qemu.sh
|
./local/scripts/test-phase4-wayland-qemu.sh
|
||||||
# Then run inside the guest:
|
# Then run inside the guest:
|
||||||
# redbear-phase4-wayland-check
|
# redbear-phase4-wayland-check
|
||||||
@@ -338,18 +326,15 @@ scripts/build-iso.sh redbear-grub-live-full
|
|||||||
# redbear-netctl user-facing alias
|
# redbear-netctl user-facing alias
|
||||||
redbear-netctl --help
|
redbear-netctl --help
|
||||||
|
|
||||||
# Or manually:
|
|
||||||
make all CONFIG_NAME=redbear-full
|
|
||||||
|
|
||||||
# Single custom recipe:
|
# Single custom recipe:
|
||||||
./target/release/repo cook local/recipes/branding/redbear-release
|
./target/release/repo cook local/recipes/branding/redbear-release
|
||||||
./target/release/repo cook local/recipes/system/redbear-meta
|
./target/release/repo cook local/recipes/system/redbear-meta
|
||||||
./target/release/repo cook local/recipes/core/ext4d
|
./target/release/repo cook local/recipes/core/ext4d
|
||||||
./target/release/repo cook local/recipes/core/grub # GRUB bootloader (host build, produces EFI binary)
|
./target/release/repo cook local/recipes/core/grub # GRUB bootloader (host build, produces EFI binary)
|
||||||
|
|
||||||
# GRUB boot manager (installer-native, Phase 2):
|
# GRUB boot manager (installer-native):
|
||||||
make r.grub # Build GRUB recipe
|
make r.grub # Build GRUB recipe
|
||||||
make all CONFIG_NAME=redbear-full-grub # Build with GRUB chainload
|
make all CONFIG_NAME=redbear-grub # Build text-only target with GRUB
|
||||||
# Linux-compatible CLI (add local/scripts to PATH):
|
# Linux-compatible CLI (add local/scripts to PATH):
|
||||||
grub-install --target=x86_64-efi --disk-image=build/x86_64/harddrive.img
|
grub-install --target=x86_64-efi --disk-image=build/x86_64/harddrive.img
|
||||||
grub-mkconfig -o local/recipes/core/grub/grub.cfg
|
grub-mkconfig -o local/recipes/core/grub/grub.cfg
|
||||||
@@ -463,7 +448,7 @@ ext4d/source/
|
|||||||
recipes/core/ext4d → local/recipes/core/ext4d
|
recipes/core/ext4d → local/recipes/core/ext4d
|
||||||
```
|
```
|
||||||
|
|
||||||
**Config**: ext4d is included in `config/desktop.toml` (mainline), which `redbear-desktop.toml` inherits.
|
**Config**: ext4d is included in `config/desktop.toml` (mainline), which `redbear-full.toml` inherits.
|
||||||
|
|
||||||
**Dependencies** (from workspace Cargo.toml):
|
**Dependencies** (from workspace Cargo.toml):
|
||||||
- `rsext4 = "0.3"` — Pure Rust ext4 filesystem implementation
|
- `rsext4 = "0.3"` — Pure Rust ext4 filesystem implementation
|
||||||
@@ -528,7 +513,7 @@ recipes/core/fatd → ../../local/recipes/core/fatd
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Config**: Packages included via `config/redbear-device-services.toml` (inherited by
|
**Config**: Packages included via `config/redbear-device-services.toml` (inherited by
|
||||||
`redbear-desktop.toml` and `redbear-full.toml`). Init service at
|
`redbear-full.toml` and `redbear-mini.toml`). Init service at
|
||||||
`/usr/lib/init.d/15_fatd.service`.
|
`/usr/lib/init.d/15_fatd.service`.
|
||||||
|
|
||||||
**Dependencies**: fatfs 0.3.6, fscommon 0.1.1, redox_syscall, redox-scheme, libredox, libc
|
**Dependencies**: fatfs 0.3.6, fscommon 0.1.1, redox_syscall, redox-scheme, libredox, libc
|
||||||
@@ -580,105 +565,45 @@ local/Assets/
|
|||||||
|
|
||||||
## RED BEAR OS CONFIG HIERARCHY
|
## RED BEAR OS CONFIG HIERARCHY
|
||||||
|
|
||||||
Active compile targets:
|
Active compile targets (all three work for both `make all` and `make live`):
|
||||||
|
|
||||||
Non-live (harddrive.img for QEMU / development):
|
- `redbear-full` — Desktop/graphics-enabled target
|
||||||
- `redbear-full`
|
- `redbear-mini` — Text-only console/recovery target
|
||||||
- `redbear-full-grub`
|
- `redbear-grub` — Text-only with GRUB boot manager
|
||||||
|
|
||||||
Live (ISO for real bare metal):
|
Desktop/graphics are available only on `redbear-full`.
|
||||||
- `redbear-live`
|
|
||||||
- `redbear-live-mini`
|
|
||||||
- `redbear-grub-live-full`
|
|
||||||
- `redbear-grub-live-mini`
|
|
||||||
|
|
||||||
Desktop/graphics are available only on the `full` targets. Older names such as `redbear-kde`,
|
|
||||||
`redbear-wayland`, `redbear-minimal`, and `redbear-live-minimal` may still exist in the tree as
|
|
||||||
legacy or staging artifacts, but they are not the supported compile-target surface.
|
|
||||||
|
|
||||||
```
|
```
|
||||||
redbear-grub-live-full.toml
|
|
||||||
└── redbear-live.toml (full desktop base)
|
|
||||||
└── redbear-grub.toml (GRUB policy: bootloader = "grub", efi_partition_size = 16)
|
|
||||||
|
|
||||||
redbear-grub-live-mini.toml
|
|
||||||
└── redbear-live-mini.toml (text-only live base)
|
|
||||||
└── redbear-grub.toml (GRUB policy)
|
|
||||||
|
|
||||||
redbear-live-full.toml
|
|
||||||
└── redbear-full.toml
|
|
||||||
├── desktop.toml (mainline)
|
|
||||||
├── redbear-legacy-base.toml ← Neutralize broken base legacy init scripts
|
|
||||||
├── redbear-legacy-desktop.toml ← Neutralize broken desktop legacy init scripts
|
|
||||||
├── redbear-device-services.toml ← Shared firmware-loader / evdevd / udev service wiring
|
|
||||||
├── redbear-netctl.toml ← Shared Red Bear network profile files + netctl boot service
|
|
||||||
├── redbear-greeter-services.toml ← Greeter/auth/session-launch wiring for desktop targets
|
|
||||||
└── [packages] redbear-release, redbear-hwutils, redbear-netctl,
|
|
||||||
firmware-loader, evdevd, udev-shim, redbear-info,
|
|
||||||
redbear-sessiond, redbear-authd, redbear-session-launch,
|
|
||||||
redbear-greeter, redbear-meta, cub
|
|
||||||
NOTE: Desktop/graphics are available only on redbear-full and redbear-live-full.
|
|
||||||
NOTE: ext4d is inherited from desktop.toml (mainline package).
|
|
||||||
NOTE: redbear-meta is explicitly included in redbear-full.toml; keep broader inclusion deliberate.
|
|
||||||
NOTE: redbear-live-full inherits from redbear-full.toml.
|
|
||||||
|
|
||||||
redbear-live.toml
|
|
||||||
└── redbear-full.toml
|
|
||||||
├── desktop.toml (mainline)
|
|
||||||
├── redbear-legacy-base.toml ← Neutralize broken base legacy init scripts
|
|
||||||
├── redbear-legacy-desktop.toml ← Neutralize broken desktop legacy init scripts
|
|
||||||
├── redbear-device-services.toml ← Shared firmware-loader / evdevd / udev service wiring
|
|
||||||
├── redbear-netctl.toml ← Shared Red Bear network profile files + netctl boot service
|
|
||||||
└── [packages] redbear-release, redbear-hwutils, redbear-netctl,
|
|
||||||
firmware-loader, evdevd, udev-shim, redbear-info,
|
|
||||||
redbear-sessiond, redbear-authd, redbear-session-launch,
|
|
||||||
redbear-greeter, redbear-meta, cub
|
|
||||||
NOTE: Desktop/graphics are available on redbear-live.
|
|
||||||
|
|
||||||
redbear-full.toml
|
redbear-full.toml
|
||||||
└── desktop.toml (mainline)
|
└── redbear-mini.toml
|
||||||
└── redbear-legacy-base.toml ← Neutralize broken base legacy init scripts
|
├── minimal.toml (mainline)
|
||||||
└── redbear-legacy-desktop.toml ← Neutralize broken desktop legacy init scripts
|
├── redbear-legacy-base.toml
|
||||||
└── redbear-device-services.toml ← Shared firmware-loader / evdevd / udev service wiring
|
└── redbear-netctl.toml
|
||||||
└── redbear-netctl.toml ← Shared Red Bear network profile files + netctl boot service
|
└── [packages] firmware, GPU, Wayland, Qt6, KF6, KWin, greeter, fonts, icons
|
||||||
└── redbear-greeter-services.toml ← Greeter/auth/session-launch wiring
|
└── [services] D-Bus, seatd, greeter, console
|
||||||
|
└── [users] messagebus, greeter
|
||||||
|
NOTE: ext4d is inherited from desktop.toml (mainline package).
|
||||||
|
NOTE: redbear-meta is explicitly included; keep broader inclusion deliberate.
|
||||||
|
|
||||||
redbear-full-grub.toml
|
redbear-mini.toml
|
||||||
└── redbear-full.toml
|
|
||||||
└── redbear-grub.toml (GRUB policy: bootloader = "grub", efi_partition_size = 16)
|
|
||||||
|
|
||||||
redbear-live-mini.toml
|
|
||||||
└── minimal non-desktop live target
|
|
||||||
└── desktop/graphics intentionally absent
|
|
||||||
|
|
||||||
redbear-grub-live-mini.toml
|
|
||||||
└── redbear-live-mini.toml (text-only live base)
|
|
||||||
└── redbear-grub.toml (GRUB policy)
|
|
||||||
|
|
||||||
redbear-mini
|
|
||||||
└── legacy/staging config files in-tree still use the older `redbear-minimal*` names
|
|
||||||
in some places; do not treat those names as the supported compile-target surface
|
|
||||||
|
|
||||||
redbear-minimal.toml (legacy/staging naming still present in tree)
|
|
||||||
└── minimal.toml (mainline)
|
└── minimal.toml (mainline)
|
||||||
└── base.toml
|
└── redbear-legacy-base.toml
|
||||||
└── redbear-legacy-base.toml ← Neutralize broken base legacy init scripts
|
└── redbear-netctl.toml
|
||||||
└── redbear-device-services.toml ← Shared firmware-loader / evdevd / udev service wiring
|
└── [packages] pciids, redbear-hwutils, redbear-netctl, redbear-info, cub, etc.
|
||||||
└── redbear-netctl.toml ← Shared Red Bear network profile files + netctl boot service
|
└── [services] pcid-spawner, netctl boot, console, debug console
|
||||||
└── [packages] redbear-release, redbear-hwutils, redbear-netctl,
|
|
||||||
firmware-loader, evdevd, udev-shim, redbear-info
|
redbear-grub.toml
|
||||||
|
└── redbear-mini.toml
|
||||||
|
└── redbear-grub-policy.toml (bootloader = "grub", efi_partition_size = 16)
|
||||||
|
└── [packages] grub
|
||||||
```
|
```
|
||||||
|
|
||||||
Config comparison:
|
Config comparison:
|
||||||
| Config | GPU Stack | Desktop | Branding | ext4d | GRUB | filesystem_size |
|
| Config | GPU Stack | Desktop | Branding | ext4d | GRUB | filesystem_size |
|
||||||
|--------|-----------|---------|----------|-------|------|-----------------|
|
|--------|-----------|---------|----------|-------|------|-----------------|
|
||||||
| redbear-full | Full | Yes | Yes | ✅ (via desktop.toml) | No | 4096 MiB |
|
| redbear-full | Full | Yes | Yes | ✅ | No | 4096 MiB |
|
||||||
| redbear-full-grub | Full | Yes | Yes | ✅ (via redbear-full.toml) | Yes | 4096 MiB |
|
| redbear-mini | None | None | Yes | No | No | 1536 MiB |
|
||||||
| redbear-live | Full | Yes | Yes | ✅ (via redbear-full.toml) | No | 4096 MiB |
|
| redbear-grub | None | None | Yes | No | Yes | (from mini) |
|
||||||
| redbear-grub-live-full | Full | Yes | Yes | ✅ (via redbear-full.toml) | Yes | 4096 MiB |
|
|
||||||
| redbear-live-mini | None | None | Yes | legacy/staging | No | legacy/staging |
|
|
||||||
| redbear-grub-live-mini | None | None | Yes | legacy/staging | Yes | legacy/staging |
|
|
||||||
| redbear-mini | None | None | Yes | legacy/staging naming in tree still maps through `redbear-minimal*` files | No | legacy/staging |
|
|
||||||
|
|
||||||
## ANTI-PATTERNS (COMMIT POLICY)
|
## ANTI-PATTERNS (COMMIT POLICY)
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ This work must be treated as bare-metal boot-critical substrate, not as optional
|
|||||||
Emits RB_THC_QUICKI2C, RB_UCSI_* markers. Consumes `/scheme/ucsi/summary`.
|
Emits RB_THC_QUICKI2C, RB_UCSI_* markers. Consumes `/scheme/ucsi/summary`.
|
||||||
- **`amlserde`** — AML serialization/deserialization, including `AmlSerdeValue::Buffer`
|
- **`amlserde`** — AML serialization/deserialization, including `AmlSerdeValue::Buffer`
|
||||||
(needed for `_CRS`), `RegionSpace::GenericSerialBus` for I2C/SMBus opregions.
|
(needed for `_CRS`), `RegionSpace::GenericSerialBus` for I2C/SMBus opregions.
|
||||||
- **Init services** — `redbear-live-mini.toml` wires `i2cd`, `i2c-hidd`, `i2c-dw-acpi`,
|
- **Init services** — `redbear-mini.toml` wires `i2cd`, `i2c-hidd`, `i2c-dw-acpi`,
|
||||||
`i2c-gpio-expanderd`, `intel-gpiod`, `ucsid` with non-blocking startup ordering.
|
`i2c-gpio-expanderd`, `intel-gpiod`, `ucsid` with non-blocking startup ordering.
|
||||||
|
|
||||||
### What is missing (active gaps)
|
### What is missing (active gaps)
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ Checks: [unit] section, [service] section, cmd field, non-empty data
|
|||||||
Note: Manual validation script covering `redbear-*.toml` configs. Not wired into the build system — run manually after config changes. Does not cover inherited mainline configs (minimal.toml, desktop.toml).
|
Note: Manual validation script covering `redbear-*.toml` configs. Not wired into the build system — run manually after config changes. Does not cover inherited mainline configs (minimal.toml, desktop.toml).
|
||||||
|
|
||||||
### 3C: Getty Supervisor ✅
|
### 3C: Getty Supervisor ✅
|
||||||
Init supports `respawn = true` in service TOML files. When a respawnable service's process exits, init automatically re-spawns it. All getty services across `redbear-minimal`, `redbear-desktop`, `redbear-greeter-services`, `redbear-live-mini`, `wayland`, and `redbear-kde` configs now have `respawn = true` set.
|
Init supports `respawn = true` in service TOML files. When a respawnable service's process exits, init automatically re-spawns it. All getty services across `redbear-mini`, `redbear-full`, `redbear-greeter-services`, `redbear-grub`, and `wayland` configs now have `respawn = true` set.
|
||||||
|
|
||||||
Implementation:
|
Implementation:
|
||||||
- `service.rs`: Added `respawn: bool` field to `Service` (default false). `spawn()` returns `Option<u32>` (child PID) for respawnable oneshot_async services.
|
- `service.rs`: Added `respawn: bool` field to `Service` (default false). `spawn()` returns `Option<u32>` (child PID) for respawnable oneshot_async services.
|
||||||
@@ -121,8 +121,8 @@ Status: Chain exists in rootfs only. On modern hardware without PS/2 ports, USB
|
|||||||
|
|
||||||
### Hardware Validation Requirements
|
### Hardware Validation Requirements
|
||||||
Bare-metal testing requires physical hardware. Current validation is:
|
Bare-metal testing requires physical hardware. Current validation is:
|
||||||
- **QEMU boot**: Verified for redbear-minimal and redbear-full (no panics, no parse errors, switchroot succeeds)
|
- **QEMU boot**: Verified for redbear-mini and redbear-full (no panics, no parse errors, switchroot succeeds)
|
||||||
- **Live ISO build**: redbear-live-mini and redbear-live build successfully
|
- **Live ISO build**: redbear-mini and redbear-grub build successfully
|
||||||
- **Interactive login**: Framebuffer login renders correctly (serial not available in headless QEMU)
|
- **Interactive login**: Framebuffer login renders correctly (serial not available in headless QEMU)
|
||||||
|
|
||||||
## Phase 5: Validation Matrix ✅
|
## Phase 5: Validation Matrix ✅
|
||||||
@@ -132,8 +132,7 @@ Bare-metal testing requires physical hardware. Current validation is:
|
|||||||
|--------|-------|-----------|-----------------|-------|
|
|--------|-------|-----------|-----------------|-------|
|
||||||
| redbear-mini | ✅ harddrive.img (2 GB) | ✅ Login prompt | — | Framebuffer console login |
|
| redbear-mini | ✅ harddrive.img (2 GB) | ✅ Login prompt | — | Framebuffer console login |
|
||||||
| redbear-full | ✅ harddrive.img (4 GB) | ✅ Login prompt | — | Desktop packages included |
|
| redbear-full | ✅ harddrive.img (4 GB) | ✅ Login prompt | — | Desktop packages included |
|
||||||
| redbear-live-mini | ✅ ISO (384 MB) | — | ✅ Login prompt | ISO for bare-metal boot |
|
| redbear-grub | ✅ harddrive.img | — | — | Text-only with GRUB chainload |
|
||||||
| redbear-live-full | ✅ ISO (3.0 GB) | — | — | ISO for bare-metal boot |
|
|
||||||
|
|
||||||
### Compilation Verification
|
### Compilation Verification
|
||||||
- `cargo check --workspace` in base source: **0 errors**
|
- `cargo check --workspace` in base source: **0 errors**
|
||||||
@@ -161,20 +160,20 @@ Bare-metal testing requires physical hardware. Current validation is:
|
|||||||
### Validation Commands
|
### Validation Commands
|
||||||
```bash
|
```bash
|
||||||
# Build
|
# Build
|
||||||
CI=1 make all CONFIG_NAME=redbear-minimal ARCH=x86_64
|
CI=1 make all CONFIG_NAME=redbear-mini ARCH=x86_64
|
||||||
CI=1 make all CONFIG_NAME=redbear-full ARCH=x86_64
|
CI=1 make all CONFIG_NAME=redbear-full ARCH=x86_64
|
||||||
CI=1 make live CONFIG_NAME=redbear-live-mini ARCH=x86_64
|
CI=1 make live CONFIG_NAME=redbear-mini ARCH=x86_64
|
||||||
CI=1 make live CONFIG_NAME=redbear-live-full ARCH=x86_64
|
CI=1 make live CONFIG_NAME=redbear-full ARCH=x86_64
|
||||||
|
|
||||||
# QEMU test
|
# QEMU test
|
||||||
make qemu CONFIG_NAME=redbear-minimal
|
make qemu CONFIG_NAME=redbear-mini
|
||||||
|
|
||||||
# Service file validation
|
# Service file validation
|
||||||
./local/scripts/validate-service-files.sh config/
|
./local/scripts/validate-service-files.sh config/
|
||||||
|
|
||||||
# Clean rebuild + verify
|
# Clean rebuild + verify
|
||||||
CI=1 make cr.base CONFIG_NAME=redbear-minimal ARCH=x86_64
|
CI=1 make cr.base CONFIG_NAME=redbear-mini ARCH=x86_64
|
||||||
CI=1 make all CONFIG_NAME=redbear-minimal ARCH=x86_64
|
CI=1 make all CONFIG_NAME=redbear-mini ARCH=x86_64
|
||||||
```
|
```
|
||||||
|
|
||||||
## Key Technical Findings
|
## Key Technical Findings
|
||||||
@@ -268,16 +267,15 @@ Services with `type = "oneshot_async"` are fire-and-forget by default. Init spaw
|
|||||||
|
|
||||||
### Config Include Chain
|
### Config Include Chain
|
||||||
```
|
```
|
||||||
redbear-live-full.toml → redbear-live.toml
|
|
||||||
redbear-live.toml → redbear-full.toml
|
|
||||||
redbear-full.toml → desktop.toml, redbear-legacy-base.toml, redbear-legacy-desktop.toml,
|
redbear-full.toml → desktop.toml, redbear-legacy-base.toml, redbear-legacy-desktop.toml,
|
||||||
redbear-device-services.toml, redbear-netctl.toml, redbear-greeter-services.toml
|
redbear-device-services.toml, redbear-netctl.toml, redbear-greeter-services.toml
|
||||||
desktop.toml → desktop-minimal.toml, server.toml
|
desktop.toml → desktop-minimal.toml, server.toml
|
||||||
desktop-minimal.toml → minimal.toml
|
desktop-minimal.toml → minimal.toml
|
||||||
server.toml → minimal.toml
|
server.toml → minimal.toml
|
||||||
minimal.toml → base.toml
|
minimal.toml → base.toml
|
||||||
|
|
||||||
redbear-live-mini.toml → minimal.toml, redbear-legacy-base.toml, redbear-netctl.toml
|
redbear-grub.toml → redbear-full.toml, redbear-grub-policy.toml
|
||||||
|
|
||||||
redbear-mini → redbear-minimal.toml → minimal.toml, redbear-legacy-base.toml,
|
redbear-mini → redbear-minimal.toml → minimal.toml, redbear-legacy-base.toml,
|
||||||
redbear-device-services.toml, redbear-netctl.toml
|
redbear-device-services.toml, redbear-netctl.toml
|
||||||
```
|
```
|
||||||
@@ -358,9 +356,8 @@ redbear-mini → redbear-minimal.toml → minimal.toml, redbear-legacy-base.toml
|
|||||||
| Target | Purpose | Output |
|
| Target | Purpose | Output |
|
||||||
|--------|---------|--------|
|
|--------|---------|--------|
|
||||||
| `redbear-mini` | Minimal non-desktop (QEMU + bare metal) | `build/x86_64/harddrive.img` |
|
| `redbear-mini` | Minimal non-desktop (QEMU + bare metal) | `build/x86_64/harddrive.img` |
|
||||||
| `redbear-live-mini` | Minimal live ISO (bare metal only) | `build/x86_64/redbear-live-mini.iso` |
|
| `redbear-grub` | Text-only with GRUB boot manager (bare metal) | `build/x86_64/harddrive.img` |
|
||||||
| `redbear-full` | Desktop/graphics (QEMU + bare metal) | `build/x86_64/harddrive.img` |
|
| `redbear-full` | Desktop/graphics (QEMU + bare metal) | `build/x86_64/harddrive.img` |
|
||||||
| `redbear-live-full` / `redbear-live` | Desktop/graphics live ISO (bare metal only) | `build/x86_64/redbear-live-full.iso` |
|
|
||||||
|
|
||||||
### Build commands
|
### Build commands
|
||||||
|
|
||||||
@@ -369,13 +366,13 @@ redbear-mini → redbear-minimal.toml → minimal.toml, redbear-legacy-base.toml
|
|||||||
CI=1 make all CONFIG_NAME=redbear-mini ARCH=x86_64
|
CI=1 make all CONFIG_NAME=redbear-mini ARCH=x86_64
|
||||||
|
|
||||||
# Minimal live ISO (bare-metal boot)
|
# Minimal live ISO (bare-metal boot)
|
||||||
CI=1 make live CONFIG_NAME=redbear-live-mini ARCH=x86_64
|
CI=1 make live CONFIG_NAME=redbear-mini ARCH=x86_64
|
||||||
|
|
||||||
# Desktop/graphics target (QEMU testing)
|
# Desktop/graphics target (QEMU testing)
|
||||||
CI=1 make all CONFIG_NAME=redbear-full ARCH=x86_64
|
CI=1 make all CONFIG_NAME=redbear-full ARCH=x86_64
|
||||||
|
|
||||||
# Desktop/graphics live ISO (bare-metal boot)
|
# Desktop/graphics live ISO (bare-metal boot)
|
||||||
CI=1 make live CONFIG_NAME=redbear-live-full ARCH=x86_64
|
CI=1 make live CONFIG_NAME=redbear-full ARCH=x86_64
|
||||||
```
|
```
|
||||||
|
|
||||||
### QEMU boot (harddrive.img)
|
### QEMU boot (harddrive.img)
|
||||||
@@ -399,12 +396,12 @@ graphical console, not serial.
|
|||||||
|
|
||||||
1. **Build the ISO:**
|
1. **Build the ISO:**
|
||||||
```bash
|
```bash
|
||||||
CI=1 make live CONFIG_NAME=redbear-live-mini ARCH=x86_64
|
CI=1 make live CONFIG_NAME=redbear-mini ARCH=x86_64
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Write ISO to USB drive:**
|
2. **Write ISO to USB drive:**
|
||||||
```bash
|
```bash
|
||||||
sudo dd if=build/x86_64/redbear-live-mini.iso of=/dev/sdX bs=4M status=progress && sync
|
sudo dd if=build/x86_64/redbear-live.iso of=/dev/sdX bs=4M status=progress && sync
|
||||||
```
|
```
|
||||||
Replace `/dev/sdX` with your USB device. Use `lsblk` to identify it.
|
Replace `/dev/sdX` with your USB device. Use `lsblk` to identify it.
|
||||||
|
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ hardware GPU validation → KWin session bring-up → KDE Plasma session bring-u
|
|||||||
Out of scope: USB, Wi-Fi, Bluetooth (covered by their own subsystem plans).
|
Out of scope: USB, Wi-Fi, Bluetooth (covered by their own subsystem plans).
|
||||||
|
|
||||||
Tracked-default truth: this document is the canonical desktop-path plan, and the tracked desktop-
|
Tracked-default truth: this document is the canonical desktop-path plan, and the tracked desktop-
|
||||||
capable surface is `redbear-full` / `redbear-live-full`. Older names such as `redbear-wayland` and
|
capable surface is `redbear-full`. Older names such as `redbear-wayland` and `redbear-kde`
|
||||||
`redbear-kde` should be read as historical or staging labels, not supported compile targets.
|
should be read as historical or staging labels, not supported compile targets.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ Rules:
|
|||||||
| kf6-kcmutils | builds | Widget-only build (QML stripped) | |
|
| kf6-kcmutils | builds | Widget-only build (QML stripped) | |
|
||||||
| `redbear-wayland` profile | historical / staging | Bounded Wayland validation profile | Not a supported compile target |
|
| `redbear-wayland` profile | historical / staging | Bounded Wayland validation profile | Not a supported compile target |
|
||||||
| `redbear-full` profile | builds, boots | Broader desktop plumbing profile | Session/network/runtime integration slice |
|
| `redbear-full` profile | builds, boots | Broader desktop plumbing profile | Session/network/runtime integration slice |
|
||||||
| `redbear-kde` profile | historical / staging | Older KDE session-surface profile | Not a supported compile target; use `redbear-full` / `redbear-live-full` for the tracked desktop-capable surface |
|
| `redbear-kde` profile | historical / staging | Older KDE session-surface profile | Not a supported compile target; use `redbear-full` for the tracked desktop-capable surface |
|
||||||
| bounded compositor validation path | experimental | Reaches xkbcommon init + EGL platform selection in QEMU | No complete session |
|
| bounded compositor validation path | experimental | Reaches xkbcommon init + EGL platform selection in QEMU | No complete session |
|
||||||
| qt6-wayland-smoke | builds, partial | Creates QWindow with colored background, runs 3 seconds | |
|
| qt6-wayland-smoke | builds, partial | Creates QWindow with colored background, runs 3 seconds | |
|
||||||
| QEMU graphics | usable (bounded) | Renderer is llvmpipe | Not hardware acceleration |
|
| QEMU graphics | usable (bounded) | Renderer is llvmpipe | Not hardware acceleration |
|
||||||
@@ -132,7 +132,7 @@ The repo has crossed major build-side gates:
|
|||||||
3. **Wayland/graphics packages** — libwayland, wayland-protocols, Mesa EGL+GBM+GLES2, libdrm, libdrm_amdgpu
|
3. **Wayland/graphics packages** — libwayland, wayland-protocols, Mesa EGL+GBM+GLES2, libdrm, libdrm_amdgpu
|
||||||
4. **Qt6 + D-Bus** — qtbase (7 libs + 12 plugins), qtdeclarative (11 libs), qtsvg, qtwayland, D-Bus 1.16.2
|
4. **Qt6 + D-Bus** — qtbase (7 libs + 12 plugins), qtdeclarative (11 libs), qtsvg, qtwayland, D-Bus 1.16.2
|
||||||
5. **KF6 + KDE-facing** — All 32 KF6 frameworks, kdecoration, plasma-wayland-protocols, kf6-kwayland, kf6-kcmutils
|
5. **KF6 + KDE-facing** — All 32 KF6 frameworks, kdecoration, plasma-wayland-protocols, kf6-kwayland, kf6-kcmutils
|
||||||
6. **Tracked profiles** — redbear-mini, redbear-live-mini, redbear-full, redbear-live-full
|
6. **Tracked profiles** — redbear-mini, redbear-full, redbear-grub
|
||||||
7. **Phase 1 test coverage** — 300+ unit tests across evdevd (65), udev-shim (15), firmware-loader (24), redox-drm (68), redbear-hwutils (19), and bluetooth/wifi daemons
|
7. **Phase 1 test coverage** — 300+ unit tests across evdevd (65), udev-shim (15), firmware-loader (24), redox-drm (68), redbear-hwutils (19), and bluetooth/wifi daemons
|
||||||
|
|
||||||
### What is runtime-proven (limited scope)
|
### What is runtime-proven (limited scope)
|
||||||
@@ -622,7 +622,7 @@ continuity, not as future work.
|
|||||||
| All 32 KF6 frameworks | ✅ Builds complete | Prior to this plan |
|
| All 32 KF6 frameworks | ✅ Builds complete | Prior to this plan |
|
||||||
| Input stack (libevdev, libinput, evdevd, udev-shim) | ✅ Builds complete | Prior to this plan |
|
| Input stack (libevdev, libinput, evdevd, udev-shim) | ✅ Builds complete | Prior to this plan |
|
||||||
| Mesa EGL/GBM/GLES2 + libdrm amdgpu | ✅ Builds complete | Prior to this plan |
|
| Mesa EGL/GBM/GLES2 + libdrm amdgpu | ✅ Builds complete | Prior to this plan |
|
||||||
| Desktop profiles (`redbear-mini`, `redbear-live-mini`, `redbear-full`, `redbear-live-full`) | ✅ Builds complete | Prior to this plan |
|
| Desktop profiles (`redbear-mini`, `redbear-full`, `redbear-grub`) | ✅ Builds complete | Prior to this plan |
|
||||||
| `local/docs/DBUS-INTEGRATION-PLAN.md` | D-Bus architecture, service dependency map, and phased implementation |
|
| `local/docs/DBUS-INTEGRATION-PLAN.md` | D-Bus architecture, service dependency map, and phased implementation |
|
||||||
| PRIME/DMA-BUF scheme ioctls | ✅ Implemented | Prior to this plan |
|
| PRIME/DMA-BUF scheme ioctls | ✅ Implemented | Prior to this plan |
|
||||||
| KWin recipe with 5 re-enabled features | ✅ Partial build | Prior to this plan |
|
| KWin recipe with 5 re-enabled features | ✅ Partial build | Prior to this plan |
|
||||||
|
|||||||
@@ -1084,3 +1084,102 @@ convenience layer. The remaining gap is the difference between **shipping minima
|
|||||||
implementations** and **shipping full desktop-complete service contracts** for login1,
|
implementations** and **shipping full desktop-complete service contracts** for login1,
|
||||||
Notifications, UPower, UDisks2, and PolicyKit. NetworkManager remains deferred and is not part of
|
Notifications, UPower, UDisks2, and PolicyKit. NetworkManager remains deferred and is not part of
|
||||||
the current Red Bear OS implementation scope.
|
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` | 5/5 security | Always-permit is not a production security model |
|
||||||
|
| `dbus-daemon` | 2/5 | 24-line patch is stable but not validated under real session bus load |
|
||||||
|
| `redbear-notifications` | 2-3/5 | Logs to stderr only; no ActionInvoked signal |
|
||||||
|
| `redbear-upower` | 2-3/5 | Provisional ACPI surface; no Changed signal; polling not implemented |
|
||||||
|
| `redbear-udisks` | 2-3/5 | Read-only; no mount/unmount operations |
|
||||||
|
|
||||||
|
**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 |
|
||||||
|
|---|-----|---------------|-----------------|
|
||||||
|
| 1 | `Manager.Inhibit` + `CanPowerOff`/`CanSuspend`/`CanHibernate` stubs | Missing | Return `"na"` string from each method; required by KDE's session management layer |
|
||||||
|
| 2 | `PauseDevice`/`ResumeDevice` signal emission | Declared but not emitted | Emit `uus` (major, minor, type) for PauseDevice and `uuh` (major, minor, fd) for ResumeDevice in `session.rs` when device state changes |
|
||||||
|
| 3 | Dynamic device enumeration | Static `device_map.rs` with hardcoded major/minor | Query udev-shim at runtime for major/minor -> scheme path mapping; remove hardcoded lookup table |
|
||||||
|
| 4 | Missing Session methods | `SetIdleHint`, `SetLockedHint`, `SetType`, `Terminate` not implemented | Implement these or return errors; KDE session managers call these to track session state |
|
||||||
|
|
||||||
|
### Phase 4 Gate (KDE Plasma Session) — Required D-Bus Changes
|
||||||
|
|
||||||
|
| # | Improvement | Current state | Required change |
|
||||||
|
|---|-------------|---------------|-----------------|
|
||||||
|
| 1 | `StatusNotifierWatcher` implementation | New service needed | 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 | Not implemented | Emit `ActionInvoked(uint32, string)` when user clicks notification action; expand `GetCapabilities` to include `body`, `actions`, `icon-static` |
|
||||||
|
| 7 | Stoppable daemons | Services use `pending()` with no shutdown channel | Replace `pending()` 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 |
|
||||||
|
|-----------------|--------------|---------------|----------------|
|
||||||
|
| `GetSession("auto")` | via NoopSession | No (bypasses logind) | Yes |
|
||||||
|
| `TakeControl(false)` | Via login1 | No | Yes |
|
||||||
|
| `TakeDevice(226, 0)` (DRM) | Via DeviceMap | No | Yes (critical) |
|
||||||
|
| `TakeDevice(13, 64+)` (input) | Via DeviceMap | No | Yes (critical) |
|
||||||
|
| `PauseDevice` signal | Declared, not emitted | No | Yes (critical) |
|
||||||
|
| `ResumeDevice` signal | Declared, not emitted | No | Yes (critical) |
|
||||||
|
| `Seat.SwitchTo` | Via login1 | No | Yes |
|
||||||
|
| `Manager.Inhibit` | Missing | No | Yes |
|
||||||
|
| `CanPowerOff`/`CanSuspend`/`CanHibernate` | Missing | No | Yes |
|
||||||
|
| `PrepareForShutdown` | Via ACPI | No | Yes |
|
||||||
|
| `PrepareForSleep` | Declared, not emitted | No | Yes |
|
||||||
|
|
||||||
|
### 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% |
|
||||||
|
|
||||||
|
### Missing KDE D-Bus Services
|
||||||
|
|
||||||
|
| Service | Used by | Status | Impact |
|
||||||
|
|---------|---------|--------|--------|
|
||||||
|
| `org.kde.kglobalaccel` | All KDE apps (global shortcuts) | Binary missing | HIGH |
|
||||||
|
| `org.kde.kded6` | KDE daemon (status notifier, etc.) | Binary missing | HIGH |
|
||||||
|
| `org.freedesktop.StatusNotifierWatcher` | System tray | New service needed | MEDIUM |
|
||||||
|
| `org.kde.ksmserver` | Session management | Not implemented | MEDIUM |
|
||||||
|
| `org.freedesktop.ScreenSaver` | Screen locking | Not implemented | MEDIUM |
|
||||||
|
|
||||||
|
### Implementation Priority Order
|
||||||
|
|
||||||
|
1. `redbear-sessiond` Phase 3 methods (enables DRM compositor session)
|
||||||
|
2. Dynamic device enumeration (enables non-static hardware discovery)
|
||||||
|
3. Stoppable daemons (enables testing and restart)
|
||||||
|
4. `StatusNotifierWatcher` (enables system tray)
|
||||||
|
5. `UPower` polling + signals (enables battery applet)
|
||||||
|
6. Session identity improvements (enables non-root sessions)
|
||||||
|
|||||||
@@ -31,10 +31,11 @@ greeter/auth/session-launch stack on the `redbear-full` desktop path.
|
|||||||
|
|
||||||
## Active Target Surface and Evidence Boundary
|
## Active Target Surface and Evidence Boundary
|
||||||
|
|
||||||
- The supported compile targets are `redbear-mini`, `redbear-live-mini`, `redbear-full`, and `redbear-live-full`.
|
- The supported compile targets are `redbear-mini`, `redbear-full`, and `redbear-grub`.
|
||||||
- Desktop/graphics are available only on `redbear-full` and `redbear-live-full`.
|
- Desktop/graphics are available only on `redbear-full`.
|
||||||
- Older names such as `redbear-kde`, `redbear-wayland`, and `redbear-minimal*` still appear in
|
- Older names such as `redbear-kde`, `redbear-wayland`, `redbear-minimal*`, `redbear-live-mini`,
|
||||||
historical or staging material, but they are not the supported compile-target surface.
|
and `redbear-live-full` still appear in historical or staging material, but they are not the
|
||||||
|
supported compile-target surface.
|
||||||
- The greeter/login path is currently an **experimental build/integration surface** on `redbear-full`;
|
- The greeter/login path is currently an **experimental build/integration surface** on `redbear-full`;
|
||||||
it is not yet a runtime-validated end-to-end desktop-login claim.
|
it is not yet a runtime-validated end-to-end desktop-login claim.
|
||||||
|
|
||||||
@@ -51,8 +52,8 @@ greeter/auth/session-launch stack on the `redbear-full` desktop path.
|
|||||||
| Mesa EGL+GBM+GLES2 | **builds** | Software path via LLVMpipe proven in QEMU; hardware path not proven |
|
| Mesa EGL+GBM+GLES2 | **builds** | Software path via LLVMpipe proven in QEMU; hardware path not proven |
|
||||||
| libdrm amdgpu | **builds** | Package-level success only |
|
| libdrm amdgpu | **builds** | Package-level success only |
|
||||||
| Input stack | **builds, enumerates** | evdevd (65 tests), libevdev, libinput, seatd present; evdevd registers scheme at boot; end-to-end compositor input path unproven |
|
| Input stack | **builds, enumerates** | evdevd (65 tests), libevdev, libinput, seatd present; evdevd registers scheme at boot; end-to-end compositor input path unproven |
|
||||||
| D-Bus | **builds, usable (bounded)** | System bus wired in `redbear-full`; session bus incomplete (redbear-sessiond login1 broker only) |
|
| D-Bus | **builds, bounded (in improvement)** | System bus wired in `redbear-full`; session bus incomplete; Phase 3/4 improvement plan active; completeness: login1.Manager ~10%, login1.Session ~47%, login1.Seat ~20%, Notifications ~80%, UPower ~60%, UDisks2 ~50%, PolicyKit1 ~50%; `StatusNotifierWatcher` is the new service being added in Phase 4 |
|
||||||
| redbear-sessiond | **builds, scaffold** | org.freedesktop.login1 D-Bus session broker — Rust daemon (zbus 5), wired on the `redbear-full` desktop path; now includes runtime control updates used by the greeter/auth session handoff |
|
| redbear-sessiond | **builds, scaffold (Phase 3/4 improvement active)** | org.freedesktop.login1 D-Bus session broker — Rust daemon (zbus 5), wired on the `redbear-full` desktop path; Phase 3 hard gate is TakeDevice FD passing plus PauseDevice/ResumeDevice signal emission; Priority 1 in Phase 3/4 improvement plan |
|
||||||
| redbear-authd | **builds** | Privileged local-user auth daemon; `/etc/passwd`/`/etc/shadow`/`/etc/group` parsing, SHA-256/SHA-512 crypt verification, bounded lockout, target-side recipe build proven |
|
| redbear-authd | **builds** | Privileged local-user auth daemon; `/etc/passwd`/`/etc/shadow`/`/etc/group` parsing, SHA-256/SHA-512 crypt verification, bounded lockout, target-side recipe build proven |
|
||||||
| redbear-session-launch | **builds** | User-session bootstrap tool; runtime-dir/env setup, uid/gid handoff, dbus-run-session → `redbear-kde-session`, target-side recipe build proven |
|
| redbear-session-launch | **builds** | User-session bootstrap tool; runtime-dir/env setup, uid/gid handoff, dbus-run-session → `redbear-kde-session`, target-side recipe build proven |
|
||||||
| redbear-greeterd | **builds, experimental** | Root-owned greeter orchestrator; UI/auth socket protocol, bounded restart policy, return-to-greeter daemon logic, crate tests pass; end-to-end runtime proof still pending |
|
| redbear-greeterd | **builds, experimental** | Root-owned greeter orchestrator; UI/auth socket protocol, bounded restart policy, return-to-greeter daemon logic, crate tests pass; end-to-end runtime proof still pending |
|
||||||
@@ -73,9 +74,8 @@ greeter/auth/session-launch stack on the `redbear-full` desktop path.
|
|||||||
| validation compositor runtime | **experimental** | Reaches early init in QEMU; no complete session |
|
| validation compositor runtime | **experimental** | Reaches early init in QEMU; no complete session |
|
||||||
| validation profile | **builds, boots** | Bounded Wayland runtime profile |
|
| validation profile | **builds, boots** | Bounded Wayland runtime profile |
|
||||||
| `redbear-full` profile | **builds, boots** | Active desktop/graphics compile surface; now owns the experimental greeter/auth/session-launch integration path |
|
| `redbear-full` profile | **builds, boots** | Active desktop/graphics compile surface; now owns the experimental greeter/auth/session-launch integration path |
|
||||||
| `redbear-live-full` profile | **builds** | Live image following the active desktop/graphics target |
|
| `redbear-grub` profile | **builds** | Text-only with GRUB chainload for bare-metal multi-boot |
|
||||||
| `redbear-mini` profile | **builds** | Minimal non-desktop compile target |
|
| `redbear-mini` profile | **builds** | Minimal non-desktop compile target |
|
||||||
| `redbear-live-mini` profile | **builds** | Minimal live image target |
|
|
||||||
| `redbear-hwutils` | **builds** | lspci/lsusb tools; 19 unit tests (PCI location parsing, USB device description, argument handling) |
|
| `redbear-hwutils` | **builds** | lspci/lsusb tools; 19 unit tests (PCI location parsing, USB device description, argument handling) |
|
||||||
|
|
||||||
## Profile View
|
## Profile View
|
||||||
@@ -87,11 +87,11 @@ greeter/auth/session-launch stack on the `redbear-full` desktop path.
|
|||||||
- **Use for:** Desktop integration testing, greeter/login bring-up, and bounded desktop/network plumbing validation
|
- **Use for:** Desktop integration testing, greeter/login bring-up, and bounded desktop/network plumbing validation
|
||||||
- **Do not overclaim:** This profile proves bounded QEMU desktop/network plumbing only. It does not by itself close the Wi-Fi implementation plan's later real-hardware Phase W5 reporting/recovery gate.
|
- **Do not overclaim:** This profile proves bounded QEMU desktop/network plumbing only. It does not by itself close the Wi-Fi implementation plan's later real-hardware Phase W5 reporting/recovery gate.
|
||||||
|
|
||||||
### `redbear-live-full`
|
### `redbear-grub`
|
||||||
|
|
||||||
- **Role:** Live/demo/recovery image layered on the active desktop target
|
- **Role:** Text-only target with GRUB boot manager for bare-metal multi-boot
|
||||||
- **Current truth:** Follows `redbear-full`; desktop/graphics-capable live image, but the greeter/login surface remains experimental until end-to-end proof exists
|
- **Current truth:** Follows `redbear-mini`; text-only with GRUB chainload ESP layout, no desktop/graphics
|
||||||
- **Use for:** Demo, install, and bounded live-media validation on the current desktop surface
|
- **Use for:** Bare-metal multi-boot, recovery with GRUB menu, and install workflows requiring GRUB
|
||||||
|
|
||||||
### `redbear-mini`
|
### `redbear-mini`
|
||||||
|
|
||||||
@@ -99,12 +99,6 @@ greeter/auth/session-launch stack on the `redbear-full` desktop path.
|
|||||||
- **Current truth:** No desktop/graphics path; recovery and non-desktop integration surface only. TUI recovery is bound to VT activation through `29_activate_console.service` followed by `30_console.service`/`31_debug_console.service`.
|
- **Current truth:** No desktop/graphics path; recovery and non-desktop integration surface only. TUI recovery is bound to VT activation through `29_activate_console.service` followed by `30_console.service`/`31_debug_console.service`.
|
||||||
- **Use for:** Minimal runtime bring-up, subsystem validation, and non-desktop packaging checks
|
- **Use for:** Minimal runtime bring-up, subsystem validation, and non-desktop packaging checks
|
||||||
|
|
||||||
### `redbear-live-mini`
|
|
||||||
|
|
||||||
- **Role:** Minimal live image target
|
|
||||||
- **Current truth:** No desktop/graphics path; live/recovery-oriented minimal image surface
|
|
||||||
- **Use for:** Minimal live boot and recovery workflows
|
|
||||||
|
|
||||||
## Current Blockers
|
## Current Blockers
|
||||||
|
|
||||||
### 1. Runtime trust trails build success (Phase 1 gate)
|
### 1. Runtime trust trails build success (Phase 1 gate)
|
||||||
@@ -197,7 +191,7 @@ QtNetwork is intentionally disabled because relibc networking is too narrow. Thi
|
|||||||
|
|
||||||
The Red Bear desktop stack has crossed major build-side gates and one important bounded runtime gate:
|
The Red Bear desktop stack has crossed major build-side gates and one important bounded runtime gate:
|
||||||
- All Qt6 core modules, all 32 KF6 frameworks, Mesa EGL/GBM/GLES2, and D-Bus build
|
- All Qt6 core modules, all 32 KF6 frameworks, Mesa EGL/GBM/GLES2, and D-Bus build
|
||||||
- Four supported compile targets exist, with desktop/graphics on `redbear-full` and `redbear-live-full`
|
- Four supported compile targets exist, with desktop/graphics on `redbear-full`
|
||||||
- the Red Bear-native greeter/login path now has a bounded passing QEMU proof (`GREETER_HELLO=ok`, `GREETER_INVALID=ok`, `GREETER_VALID=ok`)
|
- the Red Bear-native greeter/login path now has a bounded passing QEMU proof (`GREETER_HELLO=ok`, `GREETER_INVALID=ok`, `GREETER_VALID=ok`)
|
||||||
- relibc compatibility is materially stronger than before
|
- relibc compatibility is materially stronger than before
|
||||||
- Phase 1 test coverage is comprehensive: 300+ unit tests across all Phase 1 daemons (evdevd 65, udev-shim 15, firmware-loader 24, redox-drm 68, redbear-hwutils 19, bluetooth/wifi 209)
|
- Phase 1 test coverage is comprehensive: 300+ unit tests across all Phase 1 daemons (evdevd 65, udev-shim 15, firmware-loader 24, redox-drm 68, redbear-hwutils 19, bluetooth/wifi 209)
|
||||||
|
|||||||
@@ -75,9 +75,9 @@ recovery model.
|
|||||||
|
|
||||||
This plan assumes the Red Bear desktop direction converges on **one KDE-on-Wayland path**.
|
This plan assumes the Red Bear desktop direction converges on **one KDE-on-Wayland path**.
|
||||||
|
|
||||||
Current implementation answer: the first tracked owner is `redbear-full` (and therefore
|
Current implementation answer: the first tracked owner is `redbear-full`. Older names such
|
||||||
`redbear-live-full` for live media). Older names such as `redbear-kde` may still appear in
|
as `redbear-kde` may still appear in historical or staging material, but they are not the
|
||||||
historical or staging material, but they are not the supported compile-target surface for this plan.
|
supported compile-target surface for this plan.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -866,8 +866,7 @@ The greeter **recipe**, not the config fragment, should own staged runtime artif
|
|||||||
4. Is `dbus-run-session` reliable enough on Red Bear, or should the current `dbus-launch` path remain the first shipped session-bus strategy?
|
4. Is `dbus-run-session` reliable enough on Red Bear, or should the current `dbus-launch` path remain the first shipped session-bus strategy?
|
||||||
5. At what point should the project consider SDDM-class integration again, if ever?
|
5. At what point should the project consider SDDM-class integration again, if ever?
|
||||||
|
|
||||||
Current answer to (1): **`redbear-full` first**, with `redbear-live-full` inheriting that path for
|
Current answer to (1): **`redbear-full` first**.
|
||||||
live media.
|
|
||||||
|
|
||||||
Current answer to (2): **traditional `/etc/shadow` SHA-512-crypt / SHA-256-crypt first** (`$6$` / `$5$`),
|
Current answer to (2): **traditional `/etc/shadow` SHA-512-crypt / SHA-256-crypt first** (`$6$` / `$5$`),
|
||||||
with narrower support preferred over premature multi-format sprawl.
|
with narrower support preferred over premature multi-format sprawl.
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
**Date:** 2026-04-17
|
**Date:** 2026-04-17
|
||||||
**Status:** Fully implemented (build-tested, not yet runtime boot-tested). ESP formatted as FAT32
|
**Status:** Fully implemented (build-tested, not yet runtime boot-tested). ESP formatted as FAT32
|
||||||
per UEFI spec. Both Phase 1 (post-build script) and Phase 2 (installer-native) are wired.
|
per UEFI spec. Both Phase 1 (post-build script) and Phase 2 (installer-native) are wired.
|
||||||
**Remaining:** Runtime UEFI boot validation in QEMU (`make all CONFIG_NAME=redbear-full-grub && make qemu`).
|
**Remaining:** Runtime UEFI boot validation in QEMU (`make all CONFIG_NAME=redbear-grub && make qemu`).
|
||||||
**Prerequisite:** The `grub` package is included in `redbear-full-grub.toml` for clean-tree builds.
|
**Prerequisite:** The `grub` package is included in `redbear-grub.toml` for clean-tree builds.
|
||||||
**Approach:** Option A — GRUB as boot manager, chainloading Redox bootloader
|
**Approach:** Option A — GRUB as boot manager, chainloading Redox bootloader
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
@@ -257,7 +257,7 @@ ESP layout automatically.
|
|||||||
### Config Usage
|
### Config Usage
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
# config/redbear-full-grub.toml
|
# config/redbear-grub.toml
|
||||||
include = ["redbear-full.toml"]
|
include = ["redbear-full.toml"]
|
||||||
|
|
||||||
[general]
|
[general]
|
||||||
@@ -271,7 +271,7 @@ Or via CLI (note: INSTALLER_OPTS replaces defaults, so --cookbook=. must be incl
|
|||||||
make all CONFIG_NAME=redbear-full INSTALLER_OPTS="--cookbook=. --bootloader grub"
|
make all CONFIG_NAME=redbear-full INSTALLER_OPTS="--cookbook=. --bootloader grub"
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note:** The config file approach (`redbear-full-grub.toml`) is preferred over the CLI flag
|
**Note:** The config file approach (`redbear-grub.toml`) is preferred over the CLI flag
|
||||||
because INSTALLER_OPTS completely replaces the default value (`--cookbook=.`) rather than
|
because INSTALLER_OPTS completely replaces the default value (`--cookbook=.`) rather than
|
||||||
appending to it. Omitting `--cookbook=.` breaks local package resolution for GRUB.
|
appending to it. Omitting `--cookbook=.` breaks local package resolution for GRUB.
|
||||||
|
|
||||||
@@ -356,7 +356,7 @@ make qemu
|
|||||||
make r.grub
|
make r.grub
|
||||||
|
|
||||||
# Build image with GRUB config (installer fetches GRUB automatically)
|
# Build image with GRUB config (installer fetches GRUB automatically)
|
||||||
make all CONFIG_NAME=redbear-full-grub
|
make all CONFIG_NAME=redbear-grub
|
||||||
|
|
||||||
# Or via CLI flag
|
# Or via CLI flag
|
||||||
make all CONFIG_NAME=redbear-full INSTALLER_OPTS="--bootloader grub --cookbook=."
|
make all CONFIG_NAME=redbear-full INSTALLER_OPTS="--bootloader grub --cookbook=."
|
||||||
@@ -376,7 +376,7 @@ make qemu
|
|||||||
CI=1 ./target/release/repo cook grub
|
CI=1 ./target/release/repo cook grub
|
||||||
|
|
||||||
# Verify host-side installer accepts --bootloader flag
|
# Verify host-side installer accepts --bootloader flag
|
||||||
build/fstools/bin/redox_installer --bootloader=grub --config=config/redbear-full-grub.toml --list-packages
|
build/fstools/bin/redox_installer --bootloader=grub --config=config/redbear-grub.toml --list-packages
|
||||||
|
|
||||||
# Verify fat_tool.py operations
|
# Verify fat_tool.py operations
|
||||||
python3 local/scripts/fat_tool.py --help
|
python3 local/scripts/fat_tool.py --help
|
||||||
|
|||||||
@@ -681,7 +681,7 @@ helper hardening comes before broad driver cleanup, and runtime-proof/observabil
|
|||||||
|
|
||||||
**Verification**
|
**Verification**
|
||||||
|
|
||||||
- build passes: `CI=1 make r.base CONFIG_NAME=redbear-live-mini ARCH=x86_64`
|
- build passes: `CI=1 make r.base CONFIG_NAME=redbear-mini ARCH=x86_64`
|
||||||
- downstream consumers compile without errors
|
- downstream consumers compile without errors
|
||||||
|
|
||||||
### Wave 4 — Convert highest-risk consumers
|
### Wave 4 — Convert highest-risk consumers
|
||||||
@@ -740,7 +740,7 @@ sites converted on the PCIe ECAM/DTB/MCFG startup path). Only Mutex `.lock().unw
|
|||||||
|
|
||||||
**Verification**
|
**Verification**
|
||||||
|
|
||||||
- `CI=1 make cr.base CONFIG_NAME=redbear-live-mini ARCH=x86_64` — zero errors, build successful
|
- `CI=1 make cr.base CONFIG_NAME=redbear-mini ARCH=x86_64` — zero errors, build successful
|
||||||
- per-driver grep verified zero remaining panic-grade calls (only Mutex `.lock().unwrap()` kept)
|
- per-driver grep verified zero remaining panic-grade calls (only Mutex `.lock().unwrap()` kept)
|
||||||
|
|
||||||
### Wave 5 — Improve observability and proof
|
### Wave 5 — Improve observability and proof
|
||||||
|
|||||||
@@ -27,9 +27,8 @@ USB plan uses:
|
|||||||
| Profile | Intent | Key Fragments | Current support language |
|
| Profile | Intent | Key Fragments | Current support language |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| `redbear-mini` | Console + storage + wired-network baseline | `minimal.toml`, `redbear-legacy-base.toml`, `redbear-device-services.toml`, `redbear-netctl.toml` | builds / primary validation baseline / DHCP boot profile enabled / input-runtime substrate wired / USB: daemons built via base and targeted for bounded mini-profile validation |
|
| `redbear-mini` | Console + storage + wired-network baseline | `minimal.toml`, `redbear-legacy-base.toml`, `redbear-device-services.toml`, `redbear-netctl.toml` | builds / primary validation baseline / DHCP boot profile enabled / input-runtime substrate wired / USB: daemons built via base and targeted for bounded mini-profile validation |
|
||||||
| `redbear-live-mini` | Live/recovery form of the mini baseline | `redbear-live-minimal.toml`, `redbear-minimal.toml` | builds / live media variant of the mini profile for real bare metal / desktop graphics intentionally absent |
|
| `redbear-grub` | Text-only with GRUB boot manager | `redbear-mini.toml`, `redbear-grub-policy.toml` | builds / live media variant with GRUB chainload for real bare metal / desktop graphics intentionally absent |
|
||||||
| `redbear-full` | Desktop/network/session plumbing target | `desktop.toml`, `redbear-legacy-base.toml`, `redbear-legacy-desktop.toml`, `redbear-device-services.toml`, `redbear-netctl.toml`, `redbear-greeter-services.toml` | builds / boots in QEMU / active desktop-capable compile target / support claims remain evidence-qualified |
|
| `redbear-full` | Desktop/network/session plumbing target | `desktop.toml`, `redbear-legacy-base.toml`, `redbear-legacy-desktop.toml`, `redbear-device-services.toml`, `redbear-netctl.toml`, `redbear-greeter-services.toml` | builds / boots in QEMU / active desktop-capable compile target / support claims remain evidence-qualified |
|
||||||
| `redbear-live-full` | Live/recovery form of the full desktop target | `redbear-live-full.toml`, `redbear-full.toml` | builds / live desktop-capable image for real bare metal / inherits the full target surface |
|
|
||||||
|
|
||||||
## Profile Notes
|
## Profile Notes
|
||||||
|
|
||||||
@@ -46,9 +45,10 @@ USB plan uses:
|
|||||||
are bounded validation slices layered on top of the tracked compile targets, not additional
|
are bounded validation slices layered on top of the tracked compile targets, not additional
|
||||||
compile targets.
|
compile targets.
|
||||||
|
|
||||||
### `redbear-live-mini`
|
### `redbear-grub`
|
||||||
|
|
||||||
- Carries the same bounded non-graphics intent as `redbear-mini`, but in live/recovery image form.
|
- Text-only console/recovery target with GRUB boot manager for multi-boot bare-metal workflows.
|
||||||
|
- Inherits the same non-graphics intent as `redbear-mini`, but with GRUB chainload ESP layout.
|
||||||
- Should not grow desktop/session assumptions.
|
- Should not grow desktop/session assumptions.
|
||||||
|
|
||||||
### `redbear-full`
|
### `redbear-full`
|
||||||
@@ -56,22 +56,17 @@ USB plan uses:
|
|||||||
- Desktop-capable tracked target for the current Red Bear session/network/runtime plumbing surface.
|
- Desktop-capable tracked target for the current Red Bear session/network/runtime plumbing surface.
|
||||||
- Carries the broader D-Bus, greeter, seat, and desktop-oriented service surface.
|
- Carries the broader D-Bus, greeter, seat, and desktop-oriented service surface.
|
||||||
|
|
||||||
### `redbear-live-full`
|
|
||||||
|
|
||||||
- Live/demo/recovery form of the full desktop-capable target.
|
|
||||||
- Inherits the same desktop-target assumptions as `redbear-full`, but for live media workflows.
|
|
||||||
|
|
||||||
### Historical notes
|
### Historical notes
|
||||||
|
|
||||||
- Older names such as `redbear-minimal`, `redbear-desktop`, `redbear-wayland`, `redbear-kde`, and
|
- Older names such as `redbear-minimal`, `redbear-desktop`, `redbear-wayland`, `redbear-kde`,
|
||||||
`redbear-live` remain in older docs and some implementation details, but they are not the current
|
`redbear-live`, `redbear-live-mini`, and `redbear-live-full` remain in older docs and some
|
||||||
supported compile-target surface.
|
implementation details, but they are not the current supported compile-target surface.
|
||||||
|
|
||||||
### `redbear-bluetooth-experimental`
|
### `redbear-bluetooth-experimental`
|
||||||
|
|
||||||
- Standalone tracked profile for the first in-tree Bluetooth slice instead of a blanket claim about
|
- Standalone tracked profile for the first in-tree Bluetooth slice instead of a blanket claim about
|
||||||
all Red Bear images.
|
all Red Bear images.
|
||||||
- Extends `redbear-minimal` so the baseline runtime tooling is already present, then adds only the
|
- Extends `redbear-mini` so the baseline runtime tooling is already present, then adds only the
|
||||||
bounded Bluetooth pieces on top.
|
bounded Bluetooth pieces on top.
|
||||||
- Current path under active validation: QEMU/UEFI boot to login prompt plus guest-side `redbear-bluetooth-battery-check`, targeting repeated in-boot reruns, daemon-restart coverage, and one experimental battery-sensor Battery Level read-only workload.
|
- Current path under active validation: QEMU/UEFI boot to login prompt plus guest-side `redbear-bluetooth-battery-check`, targeting repeated in-boot reruns, daemon-restart coverage, and one experimental battery-sensor Battery Level read-only workload.
|
||||||
- Current support language is intentionally narrow: explicit-startup only, USB-attached transport,
|
- Current support language is intentionally narrow: explicit-startup only, USB-attached transport,
|
||||||
@@ -82,7 +77,7 @@ USB plan uses:
|
|||||||
|
|
||||||
- Standalone tracked profile for the current bounded Intel Wi-Fi slice instead of implying that the
|
- Standalone tracked profile for the current bounded Intel Wi-Fi slice instead of implying that the
|
||||||
wider desktop profiles already carry the full driver stack.
|
wider desktop profiles already carry the full driver stack.
|
||||||
- Extends `redbear-minimal` so the baseline firmware/input/reporting/profile-manager surface stays
|
- Extends `redbear-mini` so the baseline firmware/input/reporting/profile-manager surface stays
|
||||||
inherited while the Intel Wi-Fi driver package and bounded validation role remain isolated here.
|
inherited while the Intel Wi-Fi driver package and bounded validation role remain isolated here.
|
||||||
- Includes the Intel driver package (`redbear-iwlwifi`) in addition to the shared firmware,
|
- Includes the Intel driver package (`redbear-iwlwifi`) in addition to the shared firmware,
|
||||||
control-plane, reporting, and profile-manager pieces.
|
control-plane, reporting, and profile-manager pieces.
|
||||||
@@ -109,6 +104,6 @@ USB plan uses:
|
|||||||
- USB error handling and correctness carry significant Red Bear patches over upstream; see
|
- USB error handling and correctness carry significant Red Bear patches over upstream; see
|
||||||
`local/patches/base/redox.patch` and `local/docs/USB-IMPLEMENTATION-PLAN.md` for details.
|
`local/patches/base/redox.patch` and `local/docs/USB-IMPLEMENTATION-PLAN.md` for details.
|
||||||
- The in-tree mini image is still assembled through legacy `redbear-minimal*` config files in some
|
- The in-tree mini image is still assembled through legacy `redbear-minimal*` config files in some
|
||||||
places, but the supported compile-target names are `redbear-mini` and `redbear-live-mini`.
|
places, but the supported compile-target names are `redbear-mini` and `redbear-grub`.
|
||||||
- `redbear-bluetooth-experimental` uses USB only as a transport for BLE dongles; it does not make a
|
- `redbear-bluetooth-experimental` uses USB only as a transport for BLE dongles; it does not make a
|
||||||
general USB-class-autospawn claim.
|
general USB-class-autospawn claim.
|
||||||
|
|||||||
@@ -126,13 +126,12 @@ In-guest quick checks:
|
|||||||
|
|
||||||
## Compile-target note
|
## Compile-target note
|
||||||
|
|
||||||
Red Bear has exactly four compile targets:
|
Red Bear has exactly three compile targets:
|
||||||
|
|
||||||
- `redbear-mini`
|
- `redbear-mini`
|
||||||
- `redbear-live-mini`
|
|
||||||
- `redbear-full`
|
- `redbear-full`
|
||||||
- `redbear-live-full`
|
- `redbear-grub`
|
||||||
|
|
||||||
Older names such as `redbear-desktop`, `redbear-wayland`, `redbear-kde`, and `redbear-minimal` may
|
Older names such as `redbear-desktop`, `redbear-wayland`, `redbear-kde`, `redbear-minimal`,
|
||||||
still appear in historical notes or implementation details, but they are not the supported
|
`redbear-live-mini`, and `redbear-live-full` may still appear in historical notes or
|
||||||
compile-target surface.
|
implementation details, but they are not the supported compile-target surface.
|
||||||
|
|||||||
@@ -18,13 +18,11 @@ reproducible, reviewable, and upstream-friendly.
|
|||||||
|
|
||||||
Tracked Red Bear profiles are:
|
Tracked Red Bear profiles are:
|
||||||
|
|
||||||
- `redbear-minimal`
|
- `redbear-mini`
|
||||||
- `redbear-bluetooth-experimental`
|
|
||||||
- `redbear-desktop`
|
|
||||||
- `redbear-full`
|
- `redbear-full`
|
||||||
- `redbear-wayland`
|
- `redbear-grub`
|
||||||
- `redbear-kde`
|
- `redbear-bluetooth-experimental`
|
||||||
- `redbear-live`
|
- `redbear-wifi-experimental`
|
||||||
|
|
||||||
Every user-visible feature should name which profile(s) it belongs to.
|
Every user-visible feature should name which profile(s) it belongs to.
|
||||||
|
|
||||||
@@ -62,7 +60,7 @@ why it is intentionally excluded.
|
|||||||
|
|
||||||
## Profile Intent
|
## Profile Intent
|
||||||
|
|
||||||
### `redbear-minimal`
|
### `redbear-mini`
|
||||||
|
|
||||||
Primary validation baseline: console, storage, package flow, and wired networking.
|
Primary validation baseline: console, storage, package flow, and wired networking.
|
||||||
|
|
||||||
@@ -71,25 +69,18 @@ Primary validation baseline: console, storage, package flow, and wired networkin
|
|||||||
First bounded Bluetooth validation profile: explicit-startup, USB-attached, BLE-first, and
|
First bounded Bluetooth validation profile: explicit-startup, USB-attached, BLE-first, and
|
||||||
experimental only.
|
experimental only.
|
||||||
|
|
||||||
### `redbear-desktop`
|
|
||||||
|
|
||||||
Supplementary integration support profile for shared Red Bear runtime services beneath the tracked KWin target.
|
|
||||||
|
|
||||||
### `redbear-full`
|
### `redbear-full`
|
||||||
|
|
||||||
Expanded integration slice that includes more runtime pieces and graphics-path bring-up beneath the tracked KWin target.
|
Desktop-capable tracked target for the current Red Bear session/network/runtime plumbing surface,
|
||||||
|
including graphics-path bring-up beneath the tracked KWin direction.
|
||||||
|
|
||||||
### `redbear-wayland`
|
### `redbear-grub`
|
||||||
|
|
||||||
Dedicated Wayland runtime validation profile layered above the current Red Bear service baseline and subordinate to the tracked KWin direction.
|
Text-only console/recovery target with GRUB boot manager for bare-metal multi-boot workflows.
|
||||||
|
|
||||||
### `redbear-kde`
|
### `redbear-wifi-experimental`
|
||||||
|
|
||||||
Dedicated KDE/Plasma bring-up profile and tracked forward desktop target.
|
Bounded Intel Wi-Fi validation profile layered on the mini baseline.
|
||||||
|
|
||||||
### `redbear-live`
|
|
||||||
|
|
||||||
Live and recovery variant layered on top of the tracked KWin desktop target.
|
|
||||||
|
|
||||||
## Change Checklist
|
## Change Checklist
|
||||||
|
|
||||||
|
|||||||
@@ -24,9 +24,6 @@ static const struct
|
|||||||
|
|
||||||
std::unique_ptr<Session> Session::create()
|
std::unique_ptr<Session> Session::create()
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_REDOX
|
|
||||||
return NoopSession::create();
|
|
||||||
#else
|
|
||||||
for (const auto &sessionInfo : s_availableSessions) {
|
for (const auto &sessionInfo : s_availableSessions) {
|
||||||
std::unique_ptr<Session> session = sessionInfo.createFunc();
|
std::unique_ptr<Session> session = sessionInfo.createFunc();
|
||||||
if (session) {
|
if (session) {
|
||||||
@@ -34,20 +31,19 @@ std::unique_ptr<Session> Session::create()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Session> Session::create(Type type)
|
std::unique_ptr<Session> Session::create(Type type)
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_REDOX
|
#ifdef Q_OS_REDOX
|
||||||
switch (type) {
|
for (const auto &sessionInfo : s_availableSessions) {
|
||||||
case Type::Logind:
|
if (sessionInfo.type == type) {
|
||||||
return NoopSession::create();
|
if (auto session = sessionInfo.createFunc()) {
|
||||||
case Type::ConsoleKit:
|
return session;
|
||||||
return ConsoleKitSession::create();
|
}
|
||||||
case Type::Noop:
|
}
|
||||||
return NoopSession::create();
|
|
||||||
}
|
}
|
||||||
|
return NoopSession::create();
|
||||||
#else
|
#else
|
||||||
for (const auto &sessionInfo : s_availableSessions) {
|
for (const auto &sessionInfo : s_availableSessions) {
|
||||||
if (sessionInfo.type == type) {
|
if (sessionInfo.type == type) {
|
||||||
|
|||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
[D-BUS Service]
|
||||||
|
Name=org.freedesktop.StatusNotifierWatcher
|
||||||
|
Exec=/usr/bin/redbear-statusnotifierwatcher
|
||||||
@@ -40,7 +40,7 @@ impl Notifications {
|
|||||||
_app_icon: &str,
|
_app_icon: &str,
|
||||||
summary: &str,
|
summary: &str,
|
||||||
body: &str,
|
body: &str,
|
||||||
_actions: Vec<String>,
|
actions: Vec<String>,
|
||||||
_hints: HashMap<String, Value<'_>>,
|
_hints: HashMap<String, Value<'_>>,
|
||||||
_expire_timeout: i32,
|
_expire_timeout: i32,
|
||||||
) -> u32 {
|
) -> u32 {
|
||||||
@@ -48,6 +48,10 @@ impl Notifications {
|
|||||||
|
|
||||||
eprintln!("notification: [{app_name}] {summary}: {body}");
|
eprintln!("notification: [{app_name}] {summary}: {body}");
|
||||||
|
|
||||||
|
for chunk in actions.chunks_exact(2) {
|
||||||
|
eprintln!("notification {id}: action key '{}'", chunk[0]);
|
||||||
|
}
|
||||||
|
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +68,11 @@ impl Notifications {
|
|||||||
|
|
||||||
#[zbus(name = "GetCapabilities")]
|
#[zbus(name = "GetCapabilities")]
|
||||||
fn get_capabilities(&self) -> Vec<String> {
|
fn get_capabilities(&self) -> Vec<String> {
|
||||||
vec!["body".to_owned()]
|
vec![
|
||||||
|
"body".to_owned(),
|
||||||
|
"body-markup".to_owned(),
|
||||||
|
"actions".to_owned(),
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus(name = "GetServerInformation")]
|
#[zbus(name = "GetServerInformation")]
|
||||||
@@ -88,6 +96,13 @@ impl Notifications {
|
|||||||
id: u32,
|
id: u32,
|
||||||
reason: u32,
|
reason: u32,
|
||||||
) -> zbus::Result<()>;
|
) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
#[zbus(signal, name = "ActionInvoked")]
|
||||||
|
async fn action_invoked(
|
||||||
|
signal_emitter: &SignalEmitter<'_>,
|
||||||
|
id: u32,
|
||||||
|
action_key: &str,
|
||||||
|
) -> zbus::Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Command {
|
enum Command {
|
||||||
@@ -115,25 +130,32 @@ fn parse_args() -> Result<Command, String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
fn spawn_signal_handler(shutdown_tx: tokio::sync::watch::Sender<bool>) {
|
||||||
async fn wait_for_shutdown() -> Result<(), Box<dyn Error>> {
|
tokio::spawn(async move {
|
||||||
use tokio::signal::unix::{SignalKind, signal};
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
let mut terminate = signal(SignalKind::terminate())?;
|
use tokio::signal::unix::{SignalKind, signal};
|
||||||
|
if let Ok(mut sigterm) = signal(SignalKind::terminate()) {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
_ = terminate.recv() => Ok(()),
|
_ = sigterm.recv() => {},
|
||||||
_ = tokio::signal::ctrl_c() => Ok(()),
|
_ = tokio::signal::ctrl_c() => {},
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
let _ = tokio::signal::ctrl_c().await;
|
||||||
#[cfg(not(unix))]
|
}
|
||||||
async fn wait_for_shutdown() -> Result<(), Box<dyn Error>> {
|
}
|
||||||
tokio::signal::ctrl_c().await?;
|
#[cfg(not(unix))]
|
||||||
Ok(())
|
{
|
||||||
|
let _ = tokio::signal::ctrl_c().await;
|
||||||
|
}
|
||||||
|
let _ = shutdown_tx.send(true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run_daemon() -> Result<(), Box<dyn Error>> {
|
async fn run_daemon() -> Result<(), Box<dyn Error>> {
|
||||||
|
let (shutdown_tx, mut shutdown_rx) = tokio::sync::watch::channel(false);
|
||||||
|
spawn_signal_handler(shutdown_tx);
|
||||||
|
|
||||||
let _connection = ConnectionBuilder::session()?
|
let _connection = ConnectionBuilder::session()?
|
||||||
.name(BUS_NAME)?
|
.name(BUS_NAME)?
|
||||||
.serve_at(OBJECT_PATH, Notifications::new())?
|
.serve_at(OBJECT_PATH, Notifications::new())?
|
||||||
@@ -142,8 +164,8 @@ async fn run_daemon() -> Result<(), Box<dyn Error>> {
|
|||||||
|
|
||||||
eprintln!("redbear-notifications: registered {BUS_NAME} on the session bus");
|
eprintln!("redbear-notifications: registered {BUS_NAME} on the session bus");
|
||||||
|
|
||||||
wait_for_shutdown().await?;
|
let _ = shutdown_rx.changed().await;
|
||||||
eprintln!("redbear-notifications: received shutdown signal, exiting cleanly");
|
eprintln!("redbear-notifications: shutdown signal received, exiting cleanly");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use std::{collections::HashMap, env, error::Error, path::Path, process, thread, time::Duration};
|
use std::{collections::HashMap, env, error::Error, process, time::Duration};
|
||||||
|
|
||||||
use tokio::runtime::Builder as RuntimeBuilder;
|
use tokio::runtime::Builder as RuntimeBuilder;
|
||||||
use zbus::{
|
use zbus::{
|
||||||
@@ -77,29 +77,26 @@ fn system_connection_builder() -> Result<ConnectionBuilder<'static>, Box<dyn Err
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(unix, not(target_os = "redox")))]
|
fn spawn_signal_handler(shutdown_tx: tokio::sync::watch::Sender<bool>) {
|
||||||
async fn wait_for_shutdown() -> Result<(), Box<dyn Error>> {
|
tokio::spawn(async move {
|
||||||
use tokio::signal::unix::{SignalKind, signal};
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
let mut terminate = signal(SignalKind::terminate())?;
|
use tokio::signal::unix::{SignalKind, signal};
|
||||||
|
if let Ok(mut sigterm) = signal(SignalKind::terminate()) {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
_ = terminate.recv() => Ok(()),
|
_ = sigterm.recv() => {},
|
||||||
_ = tokio::signal::ctrl_c() => Ok(()),
|
_ = tokio::signal::ctrl_c() => {},
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
let _ = tokio::signal::ctrl_c().await;
|
||||||
#[cfg(target_os = "redox")]
|
}
|
||||||
async fn wait_for_shutdown() -> Result<(), Box<dyn Error>> {
|
}
|
||||||
std::future::pending::<()>().await;
|
#[cfg(not(unix))]
|
||||||
#[allow(unreachable_code)]
|
{
|
||||||
Ok(())
|
let _ = tokio::signal::ctrl_c().await;
|
||||||
}
|
}
|
||||||
|
let _ = shutdown_tx.send(true);
|
||||||
#[cfg(all(not(unix), not(target_os = "redox")))]
|
});
|
||||||
async fn wait_for_shutdown() -> Result<(), Box<dyn Error>> {
|
|
||||||
tokio::signal::ctrl_c().await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interface(name = "org.freedesktop.PolicyKit1.Authority")]
|
#[interface(name = "org.freedesktop.PolicyKit1.Authority")]
|
||||||
@@ -151,6 +148,9 @@ impl PolicyKitAuthority {
|
|||||||
async fn run_daemon() -> Result<(), Box<dyn Error>> {
|
async fn run_daemon() -> Result<(), Box<dyn Error>> {
|
||||||
wait_for_dbus_socket().await;
|
wait_for_dbus_socket().await;
|
||||||
|
|
||||||
|
let (shutdown_tx, mut shutdown_rx) = tokio::sync::watch::channel(false);
|
||||||
|
spawn_signal_handler(shutdown_tx);
|
||||||
|
|
||||||
let mut last_err = None;
|
let mut last_err = None;
|
||||||
for attempt in 1..=5 {
|
for attempt in 1..=5 {
|
||||||
let _authority_path = parse_object_path(AUTHORITY_PATH)?;
|
let _authority_path = parse_object_path(AUTHORITY_PATH)?;
|
||||||
@@ -163,13 +163,16 @@ async fn run_daemon() -> Result<(), Box<dyn Error>> {
|
|||||||
{
|
{
|
||||||
Ok(connection) => {
|
Ok(connection) => {
|
||||||
eprintln!("redbear-polkit: registered {BUS_NAME} on the system bus");
|
eprintln!("redbear-polkit: registered {BUS_NAME} on the system bus");
|
||||||
wait_for_shutdown().await?;
|
let _ = shutdown_rx.changed().await;
|
||||||
|
eprintln!("redbear-polkit: shutdown signal received, exiting cleanly");
|
||||||
drop(connection);
|
drop(connection);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
if attempt < 5 {
|
if attempt < 5 {
|
||||||
eprintln!("redbear-polkit: attempt {attempt}/5 failed ({err}), retrying in 2s...");
|
eprintln!(
|
||||||
|
"redbear-polkit: attempt {attempt}/5 failed ({err}), retrying in 2s..."
|
||||||
|
);
|
||||||
tokio::time::sleep(Duration::from_secs(2)).await;
|
tokio::time::sleep(Duration::from_secs(2)).await;
|
||||||
}
|
}
|
||||||
last_err = Some(err.into());
|
last_err = Some(err.into());
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use std::{
|
|||||||
io::{BufRead, BufReader},
|
io::{BufRead, BufReader},
|
||||||
os::unix::{fs::PermissionsExt, net::UnixListener},
|
os::unix::{fs::PermissionsExt, net::UnixListener},
|
||||||
path::Path,
|
path::Path,
|
||||||
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
@@ -24,14 +25,14 @@ enum ControlMessage {
|
|||||||
ResetSession {
|
ResetSession {
|
||||||
vt: u32,
|
vt: u32,
|
||||||
},
|
},
|
||||||
|
Shutdown,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_message(runtime: &SharedRuntime, message: ControlMessage) {
|
fn apply_message(
|
||||||
let Ok(mut runtime) = runtime.write() else {
|
runtime: &SharedRuntime,
|
||||||
eprintln!("redbear-sessiond: runtime state is poisoned");
|
shutdown_tx: &tokio::sync::watch::Sender<bool>,
|
||||||
return;
|
message: ControlMessage,
|
||||||
};
|
) {
|
||||||
|
|
||||||
match message {
|
match message {
|
||||||
ControlMessage::SetSession {
|
ControlMessage::SetSession {
|
||||||
username,
|
username,
|
||||||
@@ -40,6 +41,10 @@ fn apply_message(runtime: &SharedRuntime, message: ControlMessage) {
|
|||||||
leader,
|
leader,
|
||||||
state,
|
state,
|
||||||
} => {
|
} => {
|
||||||
|
let Ok(mut runtime) = runtime.write() else {
|
||||||
|
eprintln!("redbear-sessiond: runtime state is poisoned");
|
||||||
|
return;
|
||||||
|
};
|
||||||
runtime.username = username;
|
runtime.username = username;
|
||||||
runtime.uid = uid;
|
runtime.uid = uid;
|
||||||
runtime.vt = vt;
|
runtime.vt = vt;
|
||||||
@@ -48,6 +53,10 @@ fn apply_message(runtime: &SharedRuntime, message: ControlMessage) {
|
|||||||
runtime.active = true;
|
runtime.active = true;
|
||||||
}
|
}
|
||||||
ControlMessage::ResetSession { vt } => {
|
ControlMessage::ResetSession { vt } => {
|
||||||
|
let Ok(mut runtime) = runtime.write() else {
|
||||||
|
eprintln!("redbear-sessiond: runtime state is poisoned");
|
||||||
|
return;
|
||||||
|
};
|
||||||
runtime.username = String::from("root");
|
runtime.username = String::from("root");
|
||||||
runtime.uid = 0;
|
runtime.uid = 0;
|
||||||
runtime.vt = vt;
|
runtime.vt = vt;
|
||||||
@@ -55,10 +64,18 @@ fn apply_message(runtime: &SharedRuntime, message: ControlMessage) {
|
|||||||
runtime.state = String::from("closing");
|
runtime.state = String::from("closing");
|
||||||
runtime.active = true;
|
runtime.active = true;
|
||||||
}
|
}
|
||||||
|
ControlMessage::Shutdown => {
|
||||||
|
eprintln!("redbear-sessiond: shutdown requested via control socket");
|
||||||
|
let _ = shutdown_tx.send(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_control_socket(runtime: SharedRuntime) {
|
pub fn start_control_socket(
|
||||||
|
runtime: SharedRuntime,
|
||||||
|
shutdown_tx: tokio::sync::watch::Sender<bool>,
|
||||||
|
) {
|
||||||
|
let shutdown_tx = Arc::new(shutdown_tx);
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
if Path::new(CONTROL_SOCKET_PATH).exists() {
|
if Path::new(CONTROL_SOCKET_PATH).exists() {
|
||||||
if let Err(err) = fs::remove_file(CONTROL_SOCKET_PATH) {
|
if let Err(err) = fs::remove_file(CONTROL_SOCKET_PATH) {
|
||||||
@@ -79,6 +96,7 @@ pub fn start_control_socket(runtime: SharedRuntime) {
|
|||||||
eprintln!("redbear-sessiond: failed to chmod control socket: {err}");
|
eprintln!("redbear-sessiond: failed to chmod control socket: {err}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let shutdown_ref = Arc::clone(&shutdown_tx);
|
||||||
for stream in listener.incoming() {
|
for stream in listener.incoming() {
|
||||||
let Ok(stream) = stream else {
|
let Ok(stream) = stream else {
|
||||||
continue;
|
continue;
|
||||||
@@ -89,7 +107,7 @@ pub fn start_control_socket(runtime: SharedRuntime) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
match serde_json::from_str::<ControlMessage>(line.trim()) {
|
match serde_json::from_str::<ControlMessage>(line.trim()) {
|
||||||
Ok(message) => apply_message(&runtime, message),
|
Ok(message) => apply_message(&runtime, &shutdown_ref, message),
|
||||||
Err(err) => eprintln!("redbear-sessiond: invalid control message: {err}"),
|
Err(err) => eprintln!("redbear-sessiond: invalid control message: {err}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -101,12 +119,18 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::runtime_state::shared_runtime;
|
use crate::runtime_state::shared_runtime;
|
||||||
|
|
||||||
|
fn test_shutdown_channel() -> (tokio::sync::watch::Sender<bool>, tokio::sync::watch::Receiver<bool>) {
|
||||||
|
tokio::sync::watch::channel(false)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn set_session_message_updates_runtime_state() {
|
fn set_session_message_updates_runtime_state() {
|
||||||
let runtime = shared_runtime();
|
let runtime = shared_runtime();
|
||||||
|
let (tx, _rx) = test_shutdown_channel();
|
||||||
|
|
||||||
apply_message(
|
apply_message(
|
||||||
&runtime,
|
&runtime,
|
||||||
|
&tx,
|
||||||
ControlMessage::SetSession {
|
ControlMessage::SetSession {
|
||||||
username: String::from("user"),
|
username: String::from("user"),
|
||||||
uid: 1000,
|
uid: 1000,
|
||||||
@@ -128,9 +152,11 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn reset_session_message_restores_root_scaffold() {
|
fn reset_session_message_restores_root_scaffold() {
|
||||||
let runtime = shared_runtime();
|
let runtime = shared_runtime();
|
||||||
|
let (tx, _rx) = test_shutdown_channel();
|
||||||
|
|
||||||
apply_message(
|
apply_message(
|
||||||
&runtime,
|
&runtime,
|
||||||
|
&tx,
|
||||||
ControlMessage::SetSession {
|
ControlMessage::SetSession {
|
||||||
username: String::from("user"),
|
username: String::from("user"),
|
||||||
uid: 1000,
|
uid: 1000,
|
||||||
@@ -139,7 +165,7 @@ mod tests {
|
|||||||
state: String::from("active"),
|
state: String::from("active"),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
apply_message(&runtime, ControlMessage::ResetSession { vt: 3 });
|
apply_message(&runtime, &tx, ControlMessage::ResetSession { vt: 3 });
|
||||||
|
|
||||||
let runtime = runtime.read().expect("runtime lock should remain healthy");
|
let runtime = runtime.read().expect("runtime lock should remain healthy");
|
||||||
assert_eq!(runtime.username, "root");
|
assert_eq!(runtime.username, "root");
|
||||||
@@ -170,7 +196,26 @@ mod tests {
|
|||||||
assert_eq!(leader, 99);
|
assert_eq!(leader, 99);
|
||||||
assert_eq!(state, "online");
|
assert_eq!(state, "online");
|
||||||
}
|
}
|
||||||
ControlMessage::ResetSession { .. } => panic!("expected set_session message"),
|
ControlMessage::ResetSession { .. } | ControlMessage::Shutdown => {
|
||||||
|
panic!("expected set_session message")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn shutdown_message_sends_true_on_channel() {
|
||||||
|
let runtime = shared_runtime();
|
||||||
|
let (tx, mut rx) = test_shutdown_channel();
|
||||||
|
|
||||||
|
apply_message(&runtime, &tx, ControlMessage::Shutdown);
|
||||||
|
|
||||||
|
assert!(*rx.borrow_and_update());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn shutdown_message_parses_from_json() {
|
||||||
|
let message = serde_json::from_str::<ControlMessage>(r#"{"type":"shutdown"}"#)
|
||||||
|
.expect("shutdown message should parse");
|
||||||
|
assert!(matches!(message, ControlMessage::Shutdown));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ pub struct DeviceMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DeviceMap {
|
impl DeviceMap {
|
||||||
|
#[cfg(test)]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let static_paths = HashMap::from([
|
let static_paths = HashMap::from([
|
||||||
((226, 0), String::from("/scheme/drm/card0")),
|
((226, 0), String::from("/scheme/drm/card0")),
|
||||||
@@ -31,6 +32,31 @@ impl DeviceMap {
|
|||||||
Self { static_paths }
|
Self { static_paths }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Build a device map that merges static entries with dynamically discovered
|
||||||
|
/// devices by scanning `/scheme/drm/card*` and `/dev/input/event*` at startup.
|
||||||
|
/// For each discovered path, stat is used to read the rdev (device number).
|
||||||
|
/// Entries with a nonzero rdev are inserted into the map; static entries are
|
||||||
|
/// kept as fallback when rdev is unavailable or zero.
|
||||||
|
pub fn discover() -> Self {
|
||||||
|
let mut paths = HashMap::from([
|
||||||
|
((226, 0), String::from("/scheme/drm/card0")),
|
||||||
|
((226, 1), String::from("/scheme/drm/card1")),
|
||||||
|
((13, 64), String::from("/dev/input/event0")),
|
||||||
|
((13, 65), String::from("/dev/input/event1")),
|
||||||
|
((13, 66), String::from("/dev/input/event2")),
|
||||||
|
((13, 67), String::from("/dev/input/event3")),
|
||||||
|
((29, 0), String::from("/dev/fb0")),
|
||||||
|
((1, 1), String::from("/scheme/null")),
|
||||||
|
((1, 5), String::from("/scheme/zero")),
|
||||||
|
((1, 8), String::from("/scheme/rand")),
|
||||||
|
]);
|
||||||
|
|
||||||
|
discover_scheme_drm(&mut paths);
|
||||||
|
discover_dev_input(&mut paths);
|
||||||
|
|
||||||
|
Self { static_paths: paths }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn resolve(&self, major: u32, minor: u32) -> Option<String> {
|
pub fn resolve(&self, major: u32, minor: u32) -> Option<String> {
|
||||||
if let Some(path) = self.static_paths.get(&(major, minor)) {
|
if let Some(path) = self.static_paths.get(&(major, minor)) {
|
||||||
return Some(path.clone());
|
return Some(path.clone());
|
||||||
@@ -83,6 +109,74 @@ impl DeviceMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Scan `/scheme/drm/` for `card*` entries and merge any with a nonzero rdev
|
||||||
|
/// into the provided map. Static entries are not overwritten.
|
||||||
|
fn discover_scheme_drm(paths: &mut HashMap<(u32, u32), String>) {
|
||||||
|
let entries = match fs::read_dir("/scheme/drm") {
|
||||||
|
Ok(entries) => entries,
|
||||||
|
Err(_) => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
for entry in entries.flatten() {
|
||||||
|
let path = entry.path();
|
||||||
|
let Some(name) = path.file_name().and_then(|n| n.to_str()) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if !name.starts_with("card") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
if let Ok(metadata) = fs::metadata(&path) {
|
||||||
|
let rdev = metadata.rdev();
|
||||||
|
if rdev != 0 {
|
||||||
|
let major = dev_major(rdev);
|
||||||
|
let minor = dev_minor(rdev);
|
||||||
|
paths
|
||||||
|
.entry((major, minor))
|
||||||
|
.or_insert_with(|| path.to_string_lossy().into_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(unix))]
|
||||||
|
let _ = &path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Scan `/dev/input/` for `event*` entries and merge any with a nonzero rdev
|
||||||
|
/// into the provided map. Static entries are not overwritten.
|
||||||
|
fn discover_dev_input(paths: &mut HashMap<(u32, u32), String>) {
|
||||||
|
let entries = match fs::read_dir("/dev/input") {
|
||||||
|
Ok(entries) => entries,
|
||||||
|
Err(_) => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
for entry in entries.flatten() {
|
||||||
|
let path = entry.path();
|
||||||
|
let Some(name) = path.file_name().and_then(|n| n.to_str()) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if !name.starts_with("event") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
if let Ok(metadata) = fs::metadata(&path) {
|
||||||
|
let rdev = metadata.rdev();
|
||||||
|
if rdev != 0 {
|
||||||
|
let major = dev_major(rdev);
|
||||||
|
let minor = dev_minor(rdev);
|
||||||
|
paths
|
||||||
|
.entry((major, minor))
|
||||||
|
.or_insert_with(|| path.to_string_lossy().into_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(unix))]
|
||||||
|
let _ = &path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn candidate_paths() -> Vec<PathBuf> {
|
fn candidate_paths() -> Vec<PathBuf> {
|
||||||
let mut paths = Vec::new();
|
let mut paths = Vec::new();
|
||||||
|
|
||||||
@@ -162,4 +256,12 @@ mod tests {
|
|||||||
assert_eq!(dev_major(event), 13);
|
assert_eq!(dev_major(event), 13);
|
||||||
assert_eq!(dev_minor(event), 67);
|
assert_eq!(dev_minor(event), 67);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn discover_returns_static_entries_when_no_dirs() {
|
||||||
|
let map = super::DeviceMap::discover();
|
||||||
|
assert!(map.resolve(226, 0).is_some());
|
||||||
|
assert!(map.resolve(13, 64).is_some());
|
||||||
|
assert!(map.resolve(29, 0).is_some());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ fn system_connection_builder() -> Result<ConnectionBuilder<'static>, Box<dyn Err
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(unix, not(target_os = "redox")))]
|
#[cfg(all(unix, not(target_os = "redox")))]
|
||||||
async fn wait_for_shutdown() -> Result<(), Box<dyn Error>> {
|
async fn wait_for_shutdown(mut shutdown_rx: tokio::sync::watch::Receiver<bool>) -> Result<(), Box<dyn Error>> {
|
||||||
use tokio::signal::unix::{SignalKind, signal};
|
use tokio::signal::unix::{SignalKind, signal};
|
||||||
|
|
||||||
let mut terminate = signal(SignalKind::terminate())?;
|
let mut terminate = signal(SignalKind::terminate())?;
|
||||||
@@ -92,35 +92,44 @@ async fn wait_for_shutdown() -> Result<(), Box<dyn Error>> {
|
|||||||
tokio::select! {
|
tokio::select! {
|
||||||
_ = terminate.recv() => Ok(()),
|
_ = terminate.recv() => Ok(()),
|
||||||
_ = tokio::signal::ctrl_c() => Ok(()),
|
_ = tokio::signal::ctrl_c() => Ok(()),
|
||||||
|
_ = shutdown_rx.changed() => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "redox")]
|
#[cfg(target_os = "redox")]
|
||||||
async fn wait_for_shutdown() -> Result<(), Box<dyn Error>> {
|
async fn wait_for_shutdown(mut shutdown_rx: tokio::sync::watch::Receiver<bool>) -> Result<(), Box<dyn Error>> {
|
||||||
std::future::pending::<()>().await;
|
tokio::select! {
|
||||||
|
_ = std::future::pending::<()>() => Ok(()),
|
||||||
|
_ = shutdown_rx.changed() => Ok(()),
|
||||||
|
}
|
||||||
#[allow(unreachable_code)]
|
#[allow(unreachable_code)]
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(not(unix), not(target_os = "redox")))]
|
#[cfg(all(not(unix), not(target_os = "redox")))]
|
||||||
async fn wait_for_shutdown() -> Result<(), Box<dyn Error>> {
|
async fn wait_for_shutdown(mut shutdown_rx: tokio::sync::watch::Receiver<bool>) -> Result<(), Box<dyn Error>> {
|
||||||
tokio::signal::ctrl_c().await?;
|
tokio::select! {
|
||||||
Ok(())
|
_ = tokio::signal::ctrl_c() => Ok(()),
|
||||||
|
_ = shutdown_rx.changed() => Ok(()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run_daemon() -> Result<(), Box<dyn Error>> {
|
async fn run_daemon() -> Result<(), Box<dyn Error>> {
|
||||||
wait_for_dbus_socket().await;
|
wait_for_dbus_socket().await;
|
||||||
|
|
||||||
|
let (shutdown_tx, shutdown_rx) = tokio::sync::watch::channel(false);
|
||||||
|
|
||||||
let mut last_err = None;
|
let mut last_err = None;
|
||||||
for attempt in 1..=5 {
|
for attempt in 1..=5 {
|
||||||
let session_path = parse_object_path(SESSION_PATH)?;
|
let session_path = parse_object_path(SESSION_PATH)?;
|
||||||
let seat_path = parse_object_path(SEAT_PATH)?;
|
let seat_path = parse_object_path(SEAT_PATH)?;
|
||||||
let user_path = parse_object_path(USER_PATH)?;
|
let user_path = parse_object_path(USER_PATH)?;
|
||||||
let runtime = shared_runtime();
|
let runtime = shared_runtime();
|
||||||
|
let device_map = DeviceMap::discover();
|
||||||
|
|
||||||
let session = LoginSession::new(seat_path.clone(), user_path, DeviceMap::new(), runtime.clone());
|
let session = LoginSession::new(seat_path.clone(), user_path.clone(), device_map, runtime.clone());
|
||||||
let seat = LoginSeat::new(session_path.clone(), runtime.clone());
|
let seat = LoginSeat::new(session_path.clone(), runtime.clone());
|
||||||
let manager = LoginManager::new(session_path, seat_path, runtime.clone());
|
let manager = LoginManager::new(session_path, seat_path, user_path, runtime.clone());
|
||||||
|
|
||||||
match system_connection_builder()?
|
match system_connection_builder()?
|
||||||
.name(BUS_NAME)?
|
.name(BUS_NAME)?
|
||||||
@@ -132,9 +141,9 @@ async fn run_daemon() -> Result<(), Box<dyn Error>> {
|
|||||||
{
|
{
|
||||||
Ok(connection) => {
|
Ok(connection) => {
|
||||||
eprintln!("redbear-sessiond: registered {BUS_NAME} on the system bus");
|
eprintln!("redbear-sessiond: registered {BUS_NAME} on the system bus");
|
||||||
control::start_control_socket(runtime.clone());
|
control::start_control_socket(runtime.clone(), shutdown_tx.clone());
|
||||||
tokio::spawn(acpi_watcher::watch_and_emit(connection.clone(), runtime.clone()));
|
tokio::spawn(acpi_watcher::watch_and_emit(connection.clone(), runtime.clone()));
|
||||||
wait_for_shutdown().await?;
|
wait_for_shutdown(shutdown_rx).await?;
|
||||||
drop(connection);
|
drop(connection);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +1,55 @@
|
|||||||
|
use std::{
|
||||||
|
os::fd::OwnedFd as StdOwnedFd,
|
||||||
|
os::unix::net::UnixStream,
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
use zbus::{
|
use zbus::{
|
||||||
fdo,
|
fdo,
|
||||||
interface,
|
interface,
|
||||||
object_server::SignalEmitter,
|
object_server::SignalEmitter,
|
||||||
zvariant::OwnedObjectPath,
|
zvariant::{OwnedFd, OwnedObjectPath},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::runtime_state::SharedRuntime;
|
use crate::runtime_state::{InhibitorEntry, SharedRuntime};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct LoginManager {
|
pub struct LoginManager {
|
||||||
runtime: SharedRuntime,
|
runtime: SharedRuntime,
|
||||||
session_path: OwnedObjectPath,
|
session_path: OwnedObjectPath,
|
||||||
seat_path: OwnedObjectPath,
|
seat_path: OwnedObjectPath,
|
||||||
|
user_path: OwnedObjectPath,
|
||||||
|
inhibitor_fds: Arc<Mutex<Vec<StdOwnedFd>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LoginManager {
|
impl LoginManager {
|
||||||
pub fn new(session_path: OwnedObjectPath, seat_path: OwnedObjectPath, runtime: SharedRuntime) -> Self {
|
pub fn new(
|
||||||
|
session_path: OwnedObjectPath,
|
||||||
|
seat_path: OwnedObjectPath,
|
||||||
|
user_path: OwnedObjectPath,
|
||||||
|
runtime: SharedRuntime,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
runtime,
|
runtime,
|
||||||
session_path,
|
session_path,
|
||||||
seat_path,
|
seat_path,
|
||||||
|
user_path,
|
||||||
|
inhibitor_fds: Arc::new(Mutex::new(Vec::new())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn runtime_read(&self) -> fdo::Result<std::sync::RwLockReadGuard<'_, crate::runtime_state::SessionRuntime>> {
|
||||||
|
self.runtime
|
||||||
|
.read()
|
||||||
|
.map_err(|_| fdo::Error::Failed(String::from("login1 runtime state is poisoned")))
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interface(name = "org.freedesktop.login1.Manager")]
|
#[interface(name = "org.freedesktop.login1.Manager")]
|
||||||
impl LoginManager {
|
impl LoginManager {
|
||||||
fn get_session(&self, id: &str) -> fdo::Result<OwnedObjectPath> {
|
fn get_session(&self, id: &str) -> fdo::Result<OwnedObjectPath> {
|
||||||
let runtime = self
|
let runtime = self.runtime_read()?;
|
||||||
.runtime
|
|
||||||
.read()
|
|
||||||
.map_err(|_| fdo::Error::Failed(String::from("login1 runtime state is poisoned")))?;
|
|
||||||
if id == runtime.session_id || id == "auto" {
|
if id == runtime.session_id || id == "auto" {
|
||||||
return Ok(self.session_path.clone());
|
return Ok(self.session_path.clone());
|
||||||
}
|
}
|
||||||
@@ -39,10 +58,7 @@ impl LoginManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn list_sessions(&self) -> fdo::Result<Vec<(String, u32, String, String, OwnedObjectPath)>> {
|
fn list_sessions(&self) -> fdo::Result<Vec<(String, u32, String, String, OwnedObjectPath)>> {
|
||||||
let runtime = self
|
let runtime = self.runtime_read()?;
|
||||||
.runtime
|
|
||||||
.read()
|
|
||||||
.map_err(|_| fdo::Error::Failed(String::from("login1 runtime state is poisoned")))?;
|
|
||||||
Ok(vec![(
|
Ok(vec![(
|
||||||
runtime.session_id.clone(),
|
runtime.session_id.clone(),
|
||||||
runtime.uid,
|
runtime.uid,
|
||||||
@@ -53,10 +69,7 @@ impl LoginManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_seat(&self, id: &str) -> fdo::Result<OwnedObjectPath> {
|
fn get_seat(&self, id: &str) -> fdo::Result<OwnedObjectPath> {
|
||||||
let runtime = self
|
let runtime = self.runtime_read()?;
|
||||||
.runtime
|
|
||||||
.read()
|
|
||||||
.map_err(|_| fdo::Error::Failed(String::from("login1 runtime state is poisoned")))?;
|
|
||||||
if id == runtime.seat_id {
|
if id == runtime.seat_id {
|
||||||
return Ok(self.seat_path.clone());
|
return Ok(self.seat_path.clone());
|
||||||
}
|
}
|
||||||
@@ -64,9 +77,151 @@ impl LoginManager {
|
|||||||
Err(fdo::Error::Failed(format!("unknown login1 seat '{id}'")))
|
Err(fdo::Error::Failed(format!("unknown login1 seat '{id}'")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn inhibit(&self, what: &str, who: &str, why: &str, mode: &str) -> fdo::Result<OwnedFd> {
|
||||||
|
if mode != "block" && mode != "delay" {
|
||||||
|
return Err(fdo::Error::Failed(format!(
|
||||||
|
"inhibit mode must be 'block' or 'delay', got '{mode}'"
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let (end_caller, end_daemon) = UnixStream::pair()
|
||||||
|
.map_err(|err| fdo::Error::Failed(format!("failed to create inhibit pipe: {err}")))?;
|
||||||
|
|
||||||
|
let fd_caller: StdOwnedFd = end_caller.into();
|
||||||
|
let fd_daemon: StdOwnedFd = end_daemon.into();
|
||||||
|
|
||||||
|
let uid = self.runtime_read().map(|r| r.uid).unwrap_or(0);
|
||||||
|
let pid = std::process::id();
|
||||||
|
|
||||||
|
let entry = InhibitorEntry {
|
||||||
|
what: what.to_owned(),
|
||||||
|
who: who.to_owned(),
|
||||||
|
why: why.to_owned(),
|
||||||
|
mode: mode.to_owned(),
|
||||||
|
pid,
|
||||||
|
uid,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Ok(mut runtime) = self.runtime.write() {
|
||||||
|
runtime.inhibitors.push(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(mut fds) = self.inhibitor_fds.lock() {
|
||||||
|
fds.push(fd_daemon);
|
||||||
|
}
|
||||||
|
|
||||||
|
eprintln!(
|
||||||
|
"redbear-sessiond: Inhibit(what={what}, who={who}, mode={mode}) granted"
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(OwnedFd::from(fd_caller))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_power_off(&self) -> fdo::Result<String> {
|
||||||
|
Ok(String::from("na"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_reboot(&self) -> fdo::Result<String> {
|
||||||
|
Ok(String::from("na"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_suspend(&self) -> fdo::Result<String> {
|
||||||
|
Ok(String::from("na"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_hibernate(&self) -> fdo::Result<String> {
|
||||||
|
Ok(String::from("na"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_hybrid_sleep(&self) -> fdo::Result<String> {
|
||||||
|
Ok(String::from("na"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_suspend_then_hibernate(&self) -> fdo::Result<String> {
|
||||||
|
Ok(String::from("na"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_sleep(&self) -> fdo::Result<String> {
|
||||||
|
Ok(String::from("na"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn power_off(&self, _interactive: bool) -> fdo::Result<()> {
|
||||||
|
eprintln!("redbear-sessiond: PowerOff requested");
|
||||||
|
if let Ok(mut runtime) = self.runtime.write() {
|
||||||
|
runtime.preparing_for_shutdown = true;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reboot(&self, _interactive: bool) -> fdo::Result<()> {
|
||||||
|
eprintln!("redbear-sessiond: Reboot requested");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn suspend(&self, _interactive: bool) -> fdo::Result<()> {
|
||||||
|
eprintln!("redbear-sessiond: Suspend requested");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_session_by_pid(&self, _pid: u32) -> fdo::Result<OwnedObjectPath> {
|
||||||
|
Ok(self.session_path.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn list_users(&self) -> fdo::Result<Vec<(u32, String, OwnedObjectPath)>> {
|
||||||
|
let runtime = self.runtime_read()?;
|
||||||
|
Ok(vec![(
|
||||||
|
runtime.uid,
|
||||||
|
runtime.username.clone(),
|
||||||
|
self.user_path.clone(),
|
||||||
|
)])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn list_seats(&self) -> fdo::Result<Vec<(String, OwnedObjectPath)>> {
|
||||||
|
let runtime = self.runtime_read()?;
|
||||||
|
Ok(vec![(runtime.seat_id.clone(), self.seat_path.clone())])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn list_inhibitors(&self) -> fdo::Result<Vec<(String, String, String, String, u32, u32)>> {
|
||||||
|
let runtime = self.runtime_read()?;
|
||||||
|
Ok(runtime
|
||||||
|
.inhibitors
|
||||||
|
.iter()
|
||||||
|
.map(|entry| {
|
||||||
|
(
|
||||||
|
entry.what.clone(),
|
||||||
|
entry.who.clone(),
|
||||||
|
entry.why.clone(),
|
||||||
|
entry.mode.clone(),
|
||||||
|
entry.pid,
|
||||||
|
entry.uid,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn activate_session(&self, session_id: &str) -> fdo::Result<()> {
|
||||||
|
eprintln!("redbear-sessiond: ActivateSession({session_id}) — no-op");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lock_session(&self, session_id: &str) -> fdo::Result<()> {
|
||||||
|
eprintln!("redbear-sessiond: LockSession({session_id})");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unlock_session(&self, session_id: &str) -> fdo::Result<()> {
|
||||||
|
eprintln!("redbear-sessiond: UnlockSession({session_id})");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn terminate_session(&self, session_id: &str) -> fdo::Result<()> {
|
||||||
|
eprintln!("redbear-sessiond: TerminateSession({session_id})");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[zbus(property(emits_changed_signal = "const"), name = "IdleHint")]
|
#[zbus(property(emits_changed_signal = "const"), name = "IdleHint")]
|
||||||
fn idle_hint(&self) -> bool {
|
fn idle_hint(&self) -> bool {
|
||||||
false
|
self.runtime_read().map(|r| r.idle_hint).unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus(property(emits_changed_signal = "const"), name = "IdleSinceHint")]
|
#[zbus(property(emits_changed_signal = "const"), name = "IdleSinceHint")]
|
||||||
@@ -81,12 +236,30 @@ impl LoginManager {
|
|||||||
|
|
||||||
#[zbus(property(emits_changed_signal = "const"), name = "BlockInhibited")]
|
#[zbus(property(emits_changed_signal = "const"), name = "BlockInhibited")]
|
||||||
fn block_inhibited(&self) -> String {
|
fn block_inhibited(&self) -> String {
|
||||||
String::new()
|
self.runtime_read()
|
||||||
|
.map(|r| {
|
||||||
|
r.inhibitors
|
||||||
|
.iter()
|
||||||
|
.filter(|i| i.mode == "block")
|
||||||
|
.map(|i| i.what.as_str())
|
||||||
|
.collect::<Vec<&str>>()
|
||||||
|
.join(":")
|
||||||
|
})
|
||||||
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus(property(emits_changed_signal = "const"), name = "DelayInhibited")]
|
#[zbus(property(emits_changed_signal = "const"), name = "DelayInhibited")]
|
||||||
fn delay_inhibited(&self) -> String {
|
fn delay_inhibited(&self) -> String {
|
||||||
String::new()
|
self.runtime_read()
|
||||||
|
.map(|r| {
|
||||||
|
r.inhibitors
|
||||||
|
.iter()
|
||||||
|
.filter(|i| i.mode == "delay")
|
||||||
|
.map(|i| i.what.as_str())
|
||||||
|
.collect::<Vec<&str>>()
|
||||||
|
.join(":")
|
||||||
|
})
|
||||||
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus(property(emits_changed_signal = "const"), name = "InhibitDelayMaxUSec")]
|
#[zbus(property(emits_changed_signal = "const"), name = "InhibitDelayMaxUSec")]
|
||||||
@@ -111,8 +284,7 @@ impl LoginManager {
|
|||||||
|
|
||||||
#[zbus(property(emits_changed_signal = "const"), name = "PreparingForShutdown")]
|
#[zbus(property(emits_changed_signal = "const"), name = "PreparingForShutdown")]
|
||||||
fn preparing_for_shutdown(&self) -> bool {
|
fn preparing_for_shutdown(&self) -> bool {
|
||||||
self.runtime
|
self.runtime_read()
|
||||||
.read()
|
|
||||||
.map(|runtime| runtime.preparing_for_shutdown)
|
.map(|runtime| runtime.preparing_for_shutdown)
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
@@ -132,15 +304,21 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::runtime_state::shared_runtime;
|
use crate::runtime_state::shared_runtime;
|
||||||
|
|
||||||
#[test]
|
fn test_manager() -> LoginManager {
|
||||||
fn get_session_accepts_runtime_session_id() {
|
LoginManager::new(
|
||||||
let manager = LoginManager::new(
|
|
||||||
OwnedObjectPath::try_from(String::from("/org/freedesktop/login1/session/c1"))
|
OwnedObjectPath::try_from(String::from("/org/freedesktop/login1/session/c1"))
|
||||||
.expect("session path should parse"),
|
.expect("session path should parse"),
|
||||||
OwnedObjectPath::try_from(String::from("/org/freedesktop/login1/seat/seat0"))
|
OwnedObjectPath::try_from(String::from("/org/freedesktop/login1/seat/seat0"))
|
||||||
.expect("seat path should parse"),
|
.expect("seat path should parse"),
|
||||||
|
OwnedObjectPath::try_from(String::from("/org/freedesktop/login1/user/current"))
|
||||||
|
.expect("user path should parse"),
|
||||||
shared_runtime(),
|
shared_runtime(),
|
||||||
);
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn get_session_accepts_runtime_session_id() {
|
||||||
|
let manager = test_manager();
|
||||||
|
|
||||||
let path = manager
|
let path = manager
|
||||||
.get_session("c1")
|
.get_session("c1")
|
||||||
@@ -150,13 +328,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn get_session_accepts_auto_alias() {
|
fn get_session_accepts_auto_alias() {
|
||||||
let manager = LoginManager::new(
|
let manager = test_manager();
|
||||||
OwnedObjectPath::try_from(String::from("/org/freedesktop/login1/session/c1"))
|
|
||||||
.expect("session path should parse"),
|
|
||||||
OwnedObjectPath::try_from(String::from("/org/freedesktop/login1/seat/seat0"))
|
|
||||||
.expect("seat path should parse"),
|
|
||||||
shared_runtime(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let path = manager
|
let path = manager
|
||||||
.get_session("auto")
|
.get_session("auto")
|
||||||
@@ -177,9 +349,127 @@ mod tests {
|
|||||||
.expect("session path should parse"),
|
.expect("session path should parse"),
|
||||||
OwnedObjectPath::try_from(String::from("/org/freedesktop/login1/seat/seat0"))
|
OwnedObjectPath::try_from(String::from("/org/freedesktop/login1/seat/seat0"))
|
||||||
.expect("seat path should parse"),
|
.expect("seat path should parse"),
|
||||||
|
OwnedObjectPath::try_from(String::from("/org/freedesktop/login1/user/current"))
|
||||||
|
.expect("user path should parse"),
|
||||||
runtime,
|
runtime,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(manager.preparing_for_shutdown());
|
assert!(manager.preparing_for_shutdown());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_methods_return_na() {
|
||||||
|
let manager = test_manager();
|
||||||
|
assert_eq!(manager.can_power_off().unwrap(), "na");
|
||||||
|
assert_eq!(manager.can_reboot().unwrap(), "na");
|
||||||
|
assert_eq!(manager.can_suspend().unwrap(), "na");
|
||||||
|
assert_eq!(manager.can_hibernate().unwrap(), "na");
|
||||||
|
assert_eq!(manager.can_hybrid_sleep().unwrap(), "na");
|
||||||
|
assert_eq!(manager.can_suspend_then_hibernate().unwrap(), "na");
|
||||||
|
assert_eq!(manager.can_sleep().unwrap(), "na");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn list_users_returns_runtime_user() {
|
||||||
|
let runtime = shared_runtime();
|
||||||
|
runtime.write().expect("lock").username = String::from("testuser");
|
||||||
|
runtime.write().expect("lock").uid = 1000;
|
||||||
|
|
||||||
|
let manager = LoginManager::new(
|
||||||
|
OwnedObjectPath::try_from(String::from("/org/freedesktop/login1/session/c1")).unwrap(),
|
||||||
|
OwnedObjectPath::try_from(String::from("/org/freedesktop/login1/seat/seat0")).unwrap(),
|
||||||
|
OwnedObjectPath::try_from(String::from("/org/freedesktop/login1/user/current")).unwrap(),
|
||||||
|
runtime,
|
||||||
|
);
|
||||||
|
|
||||||
|
let users = manager.list_users().expect("list_users should succeed");
|
||||||
|
assert_eq!(users.len(), 1);
|
||||||
|
assert_eq!(users[0].0, 1000);
|
||||||
|
assert_eq!(users[0].1, "testuser");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn list_seats_returns_runtime_seat() {
|
||||||
|
let manager = test_manager();
|
||||||
|
let seats = manager.list_seats().expect("list_seats should succeed");
|
||||||
|
assert_eq!(seats.len(), 1);
|
||||||
|
assert_eq!(seats[0].0, "seat0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn get_session_by_pid_returns_session_path() {
|
||||||
|
let manager = test_manager();
|
||||||
|
let path = manager.get_session_by_pid(1234).expect("should succeed");
|
||||||
|
assert_eq!(path.as_str(), "/org/freedesktop/login1/session/c1");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn list_inhibitors_empty_by_default() {
|
||||||
|
let manager = test_manager();
|
||||||
|
let inhibitors = manager.list_inhibitors().expect("should succeed");
|
||||||
|
assert!(inhibitors.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn inhibit_rejects_invalid_mode() {
|
||||||
|
let manager = test_manager();
|
||||||
|
let err = manager.inhibit("sleep", "test", "reason", "invalid").unwrap_err();
|
||||||
|
match err {
|
||||||
|
fdo::Error::Failed(msg) => assert!(msg.contains("block") || msg.contains("delay")),
|
||||||
|
other => panic!("expected Failed error, got {other:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn inhibit_tracks_entry_in_runtime() {
|
||||||
|
let runtime = shared_runtime();
|
||||||
|
let manager = LoginManager::new(
|
||||||
|
OwnedObjectPath::try_from(String::from("/org/freedesktop/login1/session/c1")).unwrap(),
|
||||||
|
OwnedObjectPath::try_from(String::from("/org/freedesktop/login1/seat/seat0")).unwrap(),
|
||||||
|
OwnedObjectPath::try_from(String::from("/org/freedesktop/login1/user/current")).unwrap(),
|
||||||
|
runtime.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let _fd = manager
|
||||||
|
.inhibit("sleep", "testapp", "testing", "block")
|
||||||
|
.expect("inhibit should succeed");
|
||||||
|
|
||||||
|
let runtime_guard = runtime.read().expect("lock");
|
||||||
|
assert_eq!(runtime_guard.inhibitors.len(), 1);
|
||||||
|
assert_eq!(runtime_guard.inhibitors[0].what, "sleep");
|
||||||
|
assert_eq!(runtime_guard.inhibitors[0].who, "testapp");
|
||||||
|
assert_eq!(runtime_guard.inhibitors[0].mode, "block");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn block_inhibited_joins_what_fields() {
|
||||||
|
let runtime = shared_runtime();
|
||||||
|
runtime.write().expect("lock").inhibitors.push(InhibitorEntry {
|
||||||
|
what: String::from("sleep"),
|
||||||
|
who: String::from("app1"),
|
||||||
|
why: String::from("r"),
|
||||||
|
mode: String::from("block"),
|
||||||
|
pid: 1,
|
||||||
|
uid: 0,
|
||||||
|
});
|
||||||
|
runtime.write().expect("lock").inhibitors.push(InhibitorEntry {
|
||||||
|
what: String::from("shutdown"),
|
||||||
|
who: String::from("app2"),
|
||||||
|
why: String::from("r"),
|
||||||
|
mode: String::from("block"),
|
||||||
|
pid: 2,
|
||||||
|
uid: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
let manager = LoginManager::new(
|
||||||
|
OwnedObjectPath::try_from(String::from("/org/freedesktop/login1/session/c1")).unwrap(),
|
||||||
|
OwnedObjectPath::try_from(String::from("/org/freedesktop/login1/seat/seat0")).unwrap(),
|
||||||
|
OwnedObjectPath::try_from(String::from("/org/freedesktop/login1/user/current")).unwrap(),
|
||||||
|
runtime,
|
||||||
|
);
|
||||||
|
|
||||||
|
let blocked = manager.block_inhibited();
|
||||||
|
assert!(blocked.contains("sleep"));
|
||||||
|
assert!(blocked.contains("shutdown"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,15 @@
|
|||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct InhibitorEntry {
|
||||||
|
pub what: String,
|
||||||
|
pub who: String,
|
||||||
|
pub why: String,
|
||||||
|
pub mode: String,
|
||||||
|
pub pid: u32,
|
||||||
|
pub uid: u32,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SessionRuntime {
|
pub struct SessionRuntime {
|
||||||
pub session_id: String,
|
pub session_id: String,
|
||||||
@@ -11,6 +21,10 @@ pub struct SessionRuntime {
|
|||||||
pub state: String,
|
pub state: String,
|
||||||
pub active: bool,
|
pub active: bool,
|
||||||
pub preparing_for_shutdown: bool,
|
pub preparing_for_shutdown: bool,
|
||||||
|
pub idle_hint: bool,
|
||||||
|
pub locked_hint: bool,
|
||||||
|
pub session_type: String,
|
||||||
|
pub inhibitors: Vec<InhibitorEntry>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for SessionRuntime {
|
impl Default for SessionRuntime {
|
||||||
@@ -25,6 +39,10 @@ impl Default for SessionRuntime {
|
|||||||
state: String::from("online"),
|
state: String::from("online"),
|
||||||
active: true,
|
active: true,
|
||||||
preparing_for_shutdown: false,
|
preparing_for_shutdown: false,
|
||||||
|
idle_hint: false,
|
||||||
|
locked_hint: false,
|
||||||
|
session_type: String::from("wayland"),
|
||||||
|
inhibitors: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -151,6 +151,54 @@ impl LoginSession {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_idle_hint(&self, idle: bool) -> fdo::Result<()> {
|
||||||
|
let runtime = self.runtime()?;
|
||||||
|
let session_id = runtime.session_id.clone();
|
||||||
|
drop(runtime);
|
||||||
|
|
||||||
|
if let Ok(mut guard) = self.runtime.write() {
|
||||||
|
guard.idle_hint = idle;
|
||||||
|
}
|
||||||
|
eprintln!("redbear-sessiond: SetIdleHint({idle}) for session {session_id}");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_locked_hint(&self, locked: bool) -> fdo::Result<()> {
|
||||||
|
let runtime = self.runtime()?;
|
||||||
|
let session_id = runtime.session_id.clone();
|
||||||
|
drop(runtime);
|
||||||
|
|
||||||
|
if let Ok(mut guard) = self.runtime.write() {
|
||||||
|
guard.locked_hint = locked;
|
||||||
|
}
|
||||||
|
eprintln!("redbear-sessiond: SetLockedHint({locked}) for session {session_id}");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_type(&self, session_type: &str) -> fdo::Result<()> {
|
||||||
|
let runtime = self.runtime()?;
|
||||||
|
let session_id = runtime.session_id.clone();
|
||||||
|
drop(runtime);
|
||||||
|
|
||||||
|
if let Ok(mut guard) = self.runtime.write() {
|
||||||
|
guard.session_type = session_type.to_owned();
|
||||||
|
}
|
||||||
|
eprintln!("redbear-sessiond: SetType({session_type}) for session {session_id}");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn terminate(&self) -> fdo::Result<()> {
|
||||||
|
let runtime = self.runtime()?;
|
||||||
|
let session_id = runtime.session_id.clone();
|
||||||
|
drop(runtime);
|
||||||
|
|
||||||
|
if let Ok(mut guard) = self.runtime.write() {
|
||||||
|
guard.state = String::from("closing");
|
||||||
|
}
|
||||||
|
eprintln!("redbear-sessiond: Terminate requested for session {session_id}");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[zbus(property(emits_changed_signal = "const"), name = "Active")]
|
#[zbus(property(emits_changed_signal = "const"), name = "Active")]
|
||||||
fn active(&self) -> bool {
|
fn active(&self) -> bool {
|
||||||
self.runtime().map(|runtime| runtime.active).unwrap_or(true)
|
self.runtime().map(|runtime| runtime.active).unwrap_or(true)
|
||||||
@@ -161,9 +209,11 @@ impl LoginSession {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus(property(emits_changed_signal = "const"), name = "Type")]
|
#[zbus(property(emits_changed_signal = "false"), name = "Type")]
|
||||||
fn kind(&self) -> String {
|
fn kind(&self) -> String {
|
||||||
String::from("wayland")
|
self.runtime()
|
||||||
|
.map(|r| r.session_type.clone())
|
||||||
|
.unwrap_or_else(|_| String::from("wayland"))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus(property(emits_changed_signal = "const"), name = "Class")]
|
#[zbus(property(emits_changed_signal = "const"), name = "Class")]
|
||||||
@@ -191,7 +241,7 @@ impl LoginSession {
|
|||||||
self.runtime().map(|runtime| runtime.session_id).unwrap_or_else(|_| String::from("c1"))
|
self.runtime().map(|runtime| runtime.session_id).unwrap_or_else(|_| String::from("c1"))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus(property(emits_changed_signal = "const"), name = "State")]
|
#[zbus(property(emits_changed_signal = "false"), name = "State")]
|
||||||
fn state(&self) -> String {
|
fn state(&self) -> String {
|
||||||
self.runtime().map(|runtime| runtime.state).unwrap_or_else(|_| String::from("online"))
|
self.runtime().map(|runtime| runtime.state).unwrap_or_else(|_| String::from("online"))
|
||||||
}
|
}
|
||||||
@@ -244,14 +294,14 @@ impl LoginSession {
|
|||||||
String::new()
|
String::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus(property(emits_changed_signal = "const"), name = "IdleHint")]
|
#[zbus(property(emits_changed_signal = "false"), name = "IdleHint")]
|
||||||
fn idle_hint(&self) -> bool {
|
fn idle_hint(&self) -> bool {
|
||||||
false
|
self.runtime().map(|r| r.idle_hint).unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus(property(emits_changed_signal = "const"), name = "LockedHint")]
|
#[zbus(property(emits_changed_signal = "false"), name = "LockedHint")]
|
||||||
fn locked_hint(&self) -> bool {
|
fn locked_hint(&self) -> bool {
|
||||||
false
|
self.runtime().map(|r| r.locked_hint).unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus(signal, name = "PauseDevice")]
|
#[zbus(signal, name = "PauseDevice")]
|
||||||
@@ -269,4 +319,108 @@ impl LoginSession {
|
|||||||
minor: u32,
|
minor: u32,
|
||||||
fd: Fd<'_>,
|
fd: Fd<'_>,
|
||||||
) -> zbus::Result<()>;
|
) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
#[zbus(signal, name = "Lock")]
|
||||||
|
async fn lock(signal_emitter: &SignalEmitter<'_>) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
#[zbus(signal, name = "Unlock")]
|
||||||
|
async fn unlock(signal_emitter: &SignalEmitter<'_>) -> zbus::Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::device_map::DeviceMap;
|
||||||
|
use crate::runtime_state::shared_runtime;
|
||||||
|
|
||||||
|
fn test_session() -> LoginSession {
|
||||||
|
LoginSession::new(
|
||||||
|
OwnedObjectPath::try_from(String::from("/org/freedesktop/login1/seat/seat0")).unwrap(),
|
||||||
|
OwnedObjectPath::try_from(String::from("/org/freedesktop/login1/user/current")).unwrap(),
|
||||||
|
DeviceMap::new(),
|
||||||
|
shared_runtime(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn set_idle_hint_updates_runtime() {
|
||||||
|
let runtime = shared_runtime();
|
||||||
|
let session = LoginSession::new(
|
||||||
|
OwnedObjectPath::try_from(String::from("/org/freedesktop/login1/seat/seat0")).unwrap(),
|
||||||
|
OwnedObjectPath::try_from(String::from("/org/freedesktop/login1/user/current")).unwrap(),
|
||||||
|
DeviceMap::new(),
|
||||||
|
runtime.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(!session.idle_hint());
|
||||||
|
session.set_idle_hint(true).unwrap();
|
||||||
|
assert!(session.idle_hint());
|
||||||
|
|
||||||
|
let guard = runtime.read().expect("lock");
|
||||||
|
assert!(guard.idle_hint);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn set_locked_hint_updates_runtime() {
|
||||||
|
let session = test_session();
|
||||||
|
assert!(!session.locked_hint());
|
||||||
|
session.set_locked_hint(true).unwrap();
|
||||||
|
assert!(session.locked_hint());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn set_type_updates_runtime() {
|
||||||
|
let runtime = shared_runtime();
|
||||||
|
let session = LoginSession::new(
|
||||||
|
OwnedObjectPath::try_from(String::from("/org/freedesktop/login1/seat/seat0")).unwrap(),
|
||||||
|
OwnedObjectPath::try_from(String::from("/org/freedesktop/login1/user/current")).unwrap(),
|
||||||
|
DeviceMap::new(),
|
||||||
|
runtime.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(session.kind(), "wayland");
|
||||||
|
session.set_type("x11").unwrap();
|
||||||
|
assert_eq!(session.kind(), "x11");
|
||||||
|
|
||||||
|
let guard = runtime.read().expect("lock");
|
||||||
|
assert_eq!(guard.session_type, "x11");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn terminate_sets_state_to_closing() {
|
||||||
|
let runtime = shared_runtime();
|
||||||
|
let session = LoginSession::new(
|
||||||
|
OwnedObjectPath::try_from(String::from("/org/freedesktop/login1/seat/seat0")).unwrap(),
|
||||||
|
OwnedObjectPath::try_from(String::from("/org/freedesktop/login1/user/current")).unwrap(),
|
||||||
|
DeviceMap::new(),
|
||||||
|
runtime.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(session.state(), "online");
|
||||||
|
session.terminate().unwrap();
|
||||||
|
assert_eq!(session.state(), "closing");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn take_control_then_take_device_rejects_duplicate() {
|
||||||
|
let session = test_session();
|
||||||
|
session.take_control(false).unwrap();
|
||||||
|
session.taken_devices().unwrap().insert((226, 0));
|
||||||
|
let err = session.take_device(226, 0).unwrap_err();
|
||||||
|
match err {
|
||||||
|
fdo::Error::Failed(msg) => assert!(msg.contains("already taken")),
|
||||||
|
other => panic!("expected Failed error, got {other:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn release_device_rejects_unknown() {
|
||||||
|
let session = test_session();
|
||||||
|
session.take_control(false).unwrap();
|
||||||
|
let err = session.release_device(226, 99).unwrap_err();
|
||||||
|
match err {
|
||||||
|
fdo::Error::Failed(msg) => assert!(msg.contains("was not taken")),
|
||||||
|
other => panic!("expected Failed error, got {other:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
[build]
|
||||||
|
template = "cargo"
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "redbear-statusnotifierwatcher"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "redbear-statusnotifierwatcher"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
zbus = { version = "5", default-features = false, features = ["tokio"] }
|
||||||
|
tokio = { version = "1", features = ["full"] }
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
use std::collections::HashSet;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use zbus::{
|
||||||
|
fdo::{self, ObjectManager},
|
||||||
|
interface,
|
||||||
|
object_server::SignalEmitter,
|
||||||
|
connection::Builder as ConnectionBuilder,
|
||||||
|
zvariant::ObjectPath,
|
||||||
|
};
|
||||||
|
|
||||||
|
const BUS_NAME: &str = "org.freedesktop.StatusNotifierWatcher";
|
||||||
|
const OBJECT_PATH: &str = "/StatusNotifierWatcher";
|
||||||
|
|
||||||
|
/// org.freedesktop.StatusNotifierWatcher D-Bus interface
|
||||||
|
/// Tracks registered system tray items and hosts for KDE Plasma.
|
||||||
|
struct StatusNotifierWatcher {
|
||||||
|
items: Arc<Mutex<HashSet<String>>>,
|
||||||
|
hosts: Arc<Mutex<HashSet<String>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[interface(name = "org.freedesktop.StatusNotifierWatcher")]
|
||||||
|
impl StatusNotifierWatcher {
|
||||||
|
// --- Methods ---
|
||||||
|
|
||||||
|
/// Register a status notifier item.
|
||||||
|
/// The item parameter is either a full object path (e.g., "/org/example/Item")
|
||||||
|
/// sent by the item itself, or a bus name (e.g., ":1.42" or "org.example.App")
|
||||||
|
/// sent via the KDE protocol extension.
|
||||||
|
async fn register_status_notifier_item(
|
||||||
|
&self,
|
||||||
|
#[zbus(signal_emitter)] signal_emitter: SignalEmitter<'_>,
|
||||||
|
item: &str,
|
||||||
|
) -> fdo::Result<()> {
|
||||||
|
let is_new = {
|
||||||
|
let mut items = self.items.lock().map_err(|e| {
|
||||||
|
fdo::Error::Failed(format!("items lock poisoned: {e}"))
|
||||||
|
})?;
|
||||||
|
items.insert(item.to_owned())
|
||||||
|
};
|
||||||
|
if is_new {
|
||||||
|
eprintln!("statusnotifierwatcher: item registered: {item}");
|
||||||
|
let _ = Self::status_notifier_item_registered(&signal_emitter, item).await;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register a status notifier host (typically the system tray panel).
|
||||||
|
async fn register_status_notifier_host(
|
||||||
|
&self,
|
||||||
|
#[zbus(signal_emitter)] signal_emitter: SignalEmitter<'_>,
|
||||||
|
host: &str,
|
||||||
|
) -> fdo::Result<()> {
|
||||||
|
let is_new = {
|
||||||
|
let mut hosts = self.hosts.lock().map_err(|e| {
|
||||||
|
fdo::Error::Failed(format!("hosts lock poisoned: {e}"))
|
||||||
|
})?;
|
||||||
|
hosts.insert(host.to_owned())
|
||||||
|
};
|
||||||
|
if is_new {
|
||||||
|
eprintln!("statusnotifierwatcher: host registered: {host}");
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Properties ---
|
||||||
|
|
||||||
|
/// List of registered status notifier item bus names / paths.
|
||||||
|
#[zbus(property)]
|
||||||
|
fn registered_status_notifier_items(&self) -> fdo::Result<Vec<String>> {
|
||||||
|
let items = self.items.lock().map_err(|e| {
|
||||||
|
fdo::Error::Failed(format!("items lock poisoned: {e}"))
|
||||||
|
})?;
|
||||||
|
Ok(items.iter().cloned().collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether at least one status notifier host is registered.
|
||||||
|
#[zbus(property)]
|
||||||
|
fn is_status_notifier_host_registered(&self) -> fdo::Result<bool> {
|
||||||
|
let hosts = self.hosts.lock().map_err(|e| {
|
||||||
|
fdo::Error::Failed(format!("hosts lock poisoned: {e}"))
|
||||||
|
})?;
|
||||||
|
Ok(!hosts.is_empty())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Protocol version (always 0 per spec).
|
||||||
|
#[zbus(property)]
|
||||||
|
fn protocol_version(&self) -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Signals ---
|
||||||
|
|
||||||
|
/// Emitted when a new status notifier item is registered.
|
||||||
|
#[zbus(signal, name = "StatusNotifierItemRegistered")]
|
||||||
|
async fn status_notifier_item_registered(
|
||||||
|
signal_emitter: &SignalEmitter<'_>,
|
||||||
|
service: &str,
|
||||||
|
) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
/// Emitted when a status notifier item is unregistered.
|
||||||
|
#[zbus(signal, name = "StatusNotifierItemUnregistered")]
|
||||||
|
async fn status_notifier_item_unregistered(
|
||||||
|
signal_emitter: &SignalEmitter<'_>,
|
||||||
|
service: &str,
|
||||||
|
) -> zbus::Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn wait_for_session_bus() {
|
||||||
|
for _ in 0..30 {
|
||||||
|
if std::env::var("DBUS_SESSION_BUS_ADDRESS").is_ok() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tokio::time::sleep(Duration::from_millis(200)).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
wait_for_session_bus().await;
|
||||||
|
|
||||||
|
let (shutdown_tx, mut shutdown_rx) = tokio::sync::watch::channel(false);
|
||||||
|
|
||||||
|
// Signal handler task for clean shutdown
|
||||||
|
let signal_tx = shutdown_tx.clone();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
use tokio::signal::unix::{SignalKind, signal};
|
||||||
|
if let Ok(mut sigterm) = signal(SignalKind::terminate()) {
|
||||||
|
tokio::select! {
|
||||||
|
_ = sigterm.recv() => {},
|
||||||
|
_ = tokio::signal::ctrl_c() => {},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let _ = tokio::signal::ctrl_c().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(not(unix))]
|
||||||
|
{
|
||||||
|
let _ = tokio::signal::ctrl_c().await;
|
||||||
|
}
|
||||||
|
let _ = signal_tx.send(true);
|
||||||
|
});
|
||||||
|
// Keep original sender alive so receiver doesn't see all-senders-dropped
|
||||||
|
let _shutdown_guard = shutdown_tx;
|
||||||
|
|
||||||
|
let watcher = StatusNotifierWatcher {
|
||||||
|
items: Arc::new(Mutex::new(HashSet::new())),
|
||||||
|
hosts: Arc::new(Mutex::new(HashSet::new())),
|
||||||
|
};
|
||||||
|
|
||||||
|
let path: ObjectPath<'_> = OBJECT_PATH.try_into()?;
|
||||||
|
let connection = ConnectionBuilder::session()?
|
||||||
|
.name(BUS_NAME)?
|
||||||
|
.serve_at(path, watcher)?
|
||||||
|
.build()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
eprintln!("statusnotifierwatcher: {BUS_NAME} registered on session bus");
|
||||||
|
|
||||||
|
// Wait for shutdown signal
|
||||||
|
let _ = shutdown_rx.changed().await;
|
||||||
|
eprintln!("statusnotifierwatcher: shutdown signal received, exiting cleanly");
|
||||||
|
drop(connection);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -4,10 +4,8 @@ mod inventory;
|
|||||||
use std::{
|
use std::{
|
||||||
env,
|
env,
|
||||||
error::Error,
|
error::Error,
|
||||||
path::Path,
|
|
||||||
process,
|
process,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
thread,
|
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -74,34 +72,34 @@ fn system_connection_builder() -> Result<ConnectionBuilder<'static>, Box<dyn Err
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(unix, not(target_os = "redox")))]
|
fn spawn_signal_handler(shutdown_tx: tokio::sync::watch::Sender<bool>) {
|
||||||
async fn wait_for_shutdown() -> Result<(), Box<dyn Error>> {
|
tokio::spawn(async move {
|
||||||
use tokio::signal::unix::{SignalKind, signal};
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
let mut terminate = signal(SignalKind::terminate())?;
|
use tokio::signal::unix::{SignalKind, signal};
|
||||||
|
if let Ok(mut sigterm) = signal(SignalKind::terminate()) {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
_ = terminate.recv() => Ok(()),
|
_ = sigterm.recv() => {},
|
||||||
_ = tokio::signal::ctrl_c() => Ok(()),
|
_ = tokio::signal::ctrl_c() => {},
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
let _ = tokio::signal::ctrl_c().await;
|
||||||
#[cfg(target_os = "redox")]
|
}
|
||||||
async fn wait_for_shutdown() -> Result<(), Box<dyn Error>> {
|
}
|
||||||
std::future::pending::<()>().await;
|
#[cfg(not(unix))]
|
||||||
#[allow(unreachable_code)]
|
{
|
||||||
Ok(())
|
let _ = tokio::signal::ctrl_c().await;
|
||||||
}
|
}
|
||||||
|
let _ = shutdown_tx.send(true);
|
||||||
#[cfg(all(not(unix), not(target_os = "redox")))]
|
});
|
||||||
async fn wait_for_shutdown() -> Result<(), Box<dyn Error>> {
|
|
||||||
tokio::signal::ctrl_c().await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run_daemon() -> Result<(), Box<dyn Error>> {
|
async fn run_daemon() -> Result<(), Box<dyn Error>> {
|
||||||
wait_for_dbus_socket().await;
|
wait_for_dbus_socket().await;
|
||||||
|
|
||||||
|
let (shutdown_tx, mut shutdown_rx) = tokio::sync::watch::channel(false);
|
||||||
|
spawn_signal_handler(shutdown_tx);
|
||||||
|
|
||||||
let mut last_err = None;
|
let mut last_err = None;
|
||||||
for attempt in 1..=5 {
|
for attempt in 1..=5 {
|
||||||
let _root_path = parse_object_path(ROOT_PATH)?;
|
let _root_path = parse_object_path(ROOT_PATH)?;
|
||||||
@@ -128,13 +126,16 @@ async fn run_daemon() -> Result<(), Box<dyn Error>> {
|
|||||||
inventory.drives().len(),
|
inventory.drives().len(),
|
||||||
inventory.blocks().len(),
|
inventory.blocks().len(),
|
||||||
);
|
);
|
||||||
wait_for_shutdown().await?;
|
let _ = shutdown_rx.changed().await;
|
||||||
|
eprintln!("redbear-udisks: shutdown signal received, exiting cleanly");
|
||||||
drop(connection);
|
drop(connection);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
if attempt < 5 {
|
if attempt < 5 {
|
||||||
eprintln!("redbear-udisks: attempt {attempt}/5 failed ({err}), retrying in 2s...");
|
eprintln!(
|
||||||
|
"redbear-udisks: attempt {attempt}/5 failed ({err}), retrying in 2s..."
|
||||||
|
);
|
||||||
tokio::time::sleep(Duration::from_secs(2)).await;
|
tokio::time::sleep(Duration::from_secs(2)).await;
|
||||||
}
|
}
|
||||||
last_err = Some(err.into());
|
last_err = Some(err.into());
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ const DEVICE_STATE_DISCHARGING: u32 = 2;
|
|||||||
const DEVICE_STATE_EMPTY: u32 = 3;
|
const DEVICE_STATE_EMPTY: u32 = 3;
|
||||||
const DEVICE_STATE_FULLY_CHARGED: u32 = 4;
|
const DEVICE_STATE_FULLY_CHARGED: u32 = 4;
|
||||||
|
|
||||||
|
const POLL_INTERVAL_SECS: u64 = 30;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct PowerRuntime {
|
struct PowerRuntime {
|
||||||
root: PathBuf,
|
root: PathBuf,
|
||||||
@@ -59,20 +61,20 @@ enum DeviceDescriptor {
|
|||||||
Battery(String),
|
Battery(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
struct AdapterState {
|
struct AdapterState {
|
||||||
native_path: String,
|
native_path: String,
|
||||||
online: bool,
|
online: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
struct BatteryState {
|
struct BatteryState {
|
||||||
native_path: String,
|
native_path: String,
|
||||||
state_bits: u64,
|
state_bits: u64,
|
||||||
percentage: Option<f64>,
|
percentage: Option<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default, PartialEq)]
|
||||||
struct PowerSnapshot {
|
struct PowerSnapshot {
|
||||||
adapters: Vec<AdapterState>,
|
adapters: Vec<AdapterState>,
|
||||||
batteries: Vec<BatteryState>,
|
batteries: Vec<BatteryState>,
|
||||||
@@ -328,31 +330,6 @@ impl PowerSnapshot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(unix, not(target_os = "redox")))]
|
|
||||||
async fn wait_for_shutdown() -> Result<(), Box<dyn Error>> {
|
|
||||||
use tokio::signal::unix::{SignalKind, signal};
|
|
||||||
|
|
||||||
let mut terminate = signal(SignalKind::terminate())?;
|
|
||||||
|
|
||||||
tokio::select! {
|
|
||||||
_ = terminate.recv() => Ok(()),
|
|
||||||
_ = tokio::signal::ctrl_c() => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "redox")]
|
|
||||||
async fn wait_for_shutdown() -> Result<(), Box<dyn Error>> {
|
|
||||||
std::future::pending::<()>().await;
|
|
||||||
#[allow(unreachable_code)]
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(not(unix), not(target_os = "redox")))]
|
|
||||||
async fn wait_for_shutdown() -> Result<(), Box<dyn Error>> {
|
|
||||||
tokio::signal::ctrl_c().await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[interface(name = "org.freedesktop.UPower")]
|
#[interface(name = "org.freedesktop.UPower")]
|
||||||
impl UPowerDaemon {
|
impl UPowerDaemon {
|
||||||
fn enumerate_devices(&self) -> Vec<OwnedObjectPath> {
|
fn enumerate_devices(&self) -> Vec<OwnedObjectPath> {
|
||||||
@@ -368,7 +345,7 @@ impl UPowerDaemon {
|
|||||||
String::from("0.1.0")
|
String::from("0.1.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zbus(property(emits_changed_signal = "const"), name = "OnBattery")]
|
#[zbus(property(emits_changed_signal = "false"), name = "OnBattery")]
|
||||||
fn on_battery(&self) -> bool {
|
fn on_battery(&self) -> bool {
|
||||||
self.runtime.snapshot().on_battery()
|
self.runtime.snapshot().on_battery()
|
||||||
}
|
}
|
||||||
@@ -476,6 +453,28 @@ impl PowerDevice {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn spawn_signal_handler(shutdown_tx: tokio::sync::watch::Sender<bool>) {
|
||||||
|
tokio::spawn(async move {
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
use tokio::signal::unix::{SignalKind, signal};
|
||||||
|
if let Ok(mut sigterm) = signal(SignalKind::terminate()) {
|
||||||
|
tokio::select! {
|
||||||
|
_ = sigterm.recv() => {},
|
||||||
|
_ = tokio::signal::ctrl_c() => {},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let _ = tokio::signal::ctrl_c().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(not(unix))]
|
||||||
|
{
|
||||||
|
let _ = tokio::signal::ctrl_c().await;
|
||||||
|
}
|
||||||
|
let _ = shutdown_tx.send(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async fn run_daemon() -> Result<(), Box<dyn Error>> {
|
async fn run_daemon() -> Result<(), Box<dyn Error>> {
|
||||||
wait_for_dbus_socket().await;
|
wait_for_dbus_socket().await;
|
||||||
let runtime = PowerRuntime::discover()?;
|
let runtime = PowerRuntime::discover()?;
|
||||||
@@ -486,6 +485,9 @@ async fn run_daemon() -> Result<(), Box<dyn Error>> {
|
|||||||
}
|
}
|
||||||
let _display_device_path = parse_object_path(DISPLAY_DEVICE_PATH)?;
|
let _display_device_path = parse_object_path(DISPLAY_DEVICE_PATH)?;
|
||||||
|
|
||||||
|
let (shutdown_tx, mut shutdown_rx) = tokio::sync::watch::channel(false);
|
||||||
|
spawn_signal_handler(shutdown_tx);
|
||||||
|
|
||||||
let mut last_err = None;
|
let mut last_err = None;
|
||||||
for attempt in 1..=5 {
|
for attempt in 1..=5 {
|
||||||
let mut builder = system_connection_builder()?
|
let mut builder = system_connection_builder()?
|
||||||
@@ -527,13 +529,44 @@ async fn run_daemon() -> Result<(), Box<dyn Error>> {
|
|||||||
match builder.build().await {
|
match builder.build().await {
|
||||||
Ok(connection) => {
|
Ok(connection) => {
|
||||||
eprintln!("redbear-upower: registered {BUS_NAME} on the system bus");
|
eprintln!("redbear-upower: registered {BUS_NAME} on the system bus");
|
||||||
wait_for_shutdown().await?;
|
|
||||||
|
let upower_path = parse_object_path(UPOWER_PATH)?;
|
||||||
|
let signal_emitter = SignalEmitter::new(&connection, upower_path)?;
|
||||||
|
|
||||||
|
let mut last_snapshot = runtime.snapshot();
|
||||||
|
let mut poll_interval =
|
||||||
|
tokio::time::interval(Duration::from_secs(POLL_INTERVAL_SECS));
|
||||||
|
|
||||||
|
loop {
|
||||||
|
tokio::select! {
|
||||||
|
result = shutdown_rx.changed() => {
|
||||||
|
if result.is_err() {
|
||||||
|
eprintln!("redbear-upower: signal handler exited unexpectedly");
|
||||||
|
}
|
||||||
|
eprintln!("redbear-upower: shutdown signal received, exiting cleanly");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ = poll_interval.tick() => {
|
||||||
|
let current_snapshot = runtime.snapshot();
|
||||||
|
if current_snapshot != last_snapshot {
|
||||||
|
eprintln!(
|
||||||
|
"redbear-upower: power state changed, emitting Changed signal"
|
||||||
|
);
|
||||||
|
let _ = UPowerDaemon::changed(&signal_emitter).await;
|
||||||
|
last_snapshot = current_snapshot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
drop(connection);
|
drop(connection);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
if attempt < 5 {
|
if attempt < 5 {
|
||||||
eprintln!("redbear-upower: attempt {attempt}/5 failed ({err}), retrying in 2s...");
|
eprintln!(
|
||||||
|
"redbear-upower: attempt {attempt}/5 failed ({err}), retrying in 2s..."
|
||||||
|
);
|
||||||
tokio::time::sleep(Duration::from_secs(2)).await;
|
tokio::time::sleep(Duration::from_secs(2)).await;
|
||||||
}
|
}
|
||||||
last_err = Some(err.into());
|
last_err = Some(err.into());
|
||||||
|
|||||||
@@ -1,20 +1,4 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# build-redbear.sh — Build Red Bear OS from upstream base + Red Bear overlay
|
|
||||||
#
|
|
||||||
# Usage:
|
|
||||||
# ./local/scripts/build-redbear.sh # Default: redbear-full
|
|
||||||
# ./local/scripts/build-redbear.sh redbear-mini # Minimal validation baseline
|
|
||||||
# ./local/scripts/build-redbear.sh redbear-full # Full Red Bear desktop/session target
|
|
||||||
# ./local/scripts/build-redbear.sh redbear-live # Canonical full live profile config
|
|
||||||
# ./local/scripts/build-redbear.sh redbear-live-mini # Text-only mini live profile config
|
|
||||||
# ./local/scripts/build-redbear.sh redbear-grub-live-mini # Text-only GRUB mini live profile config
|
|
||||||
# ./local/scripts/build-redbear.sh --upstream redbear-full # Allow Redox/upstream recipe refresh
|
|
||||||
# APPLY_PATCHES=0 ./local/scripts/build-redbear.sh # Skip patch application
|
|
||||||
#
|
|
||||||
# This script assumes the Red Bear overlay model:
|
|
||||||
# - upstream-owned sources are refreshable working trees
|
|
||||||
# - Red Bear-owned shipping deltas live in local/patches/ and local/recipes/
|
|
||||||
# - upstream WIP recipes are not trusted as stable shipping inputs until upstream promotes them
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
@@ -25,23 +9,6 @@ JOBS="${JOBS:-$(nproc)}"
|
|||||||
APPLY_PATCHES="${APPLY_PATCHES:-1}"
|
APPLY_PATCHES="${APPLY_PATCHES:-1}"
|
||||||
ALLOW_UPSTREAM=0
|
ALLOW_UPSTREAM=0
|
||||||
|
|
||||||
canonicalize_config() {
|
|
||||||
case "$1" in
|
|
||||||
redbear-mini)
|
|
||||||
printf '%s\n' "redbear-minimal"
|
|
||||||
;;
|
|
||||||
redbear-live-full)
|
|
||||||
printf '%s\n' "redbear-live"
|
|
||||||
;;
|
|
||||||
redbear-live-mini-grub)
|
|
||||||
printf '%s\n' "redbear-grub-live-mini"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
printf '%s\n' "$1"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
Usage: $(basename "$0") [OPTIONS] [CONFIG]
|
Usage: $(basename "$0") [OPTIONS] [CONFIG]
|
||||||
@@ -53,7 +20,9 @@ Options:
|
|||||||
-h, --help Show this help
|
-h, --help Show this help
|
||||||
|
|
||||||
Configs:
|
Configs:
|
||||||
redbear-mini, redbear-full, redbear-live, redbear-live-mini, redbear-grub-live-mini
|
redbear-full Desktop/graphics target (default)
|
||||||
|
redbear-mini Text-only console/recovery target
|
||||||
|
redbear-grub Text-only with GRUB boot manager
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,22 +56,12 @@ fi
|
|||||||
|
|
||||||
[ ${#POSITIONAL[@]} -eq 1 ] && CONFIG="${POSITIONAL[0]}"
|
[ ${#POSITIONAL[@]} -eq 1 ] && CONFIG="${POSITIONAL[0]}"
|
||||||
|
|
||||||
CONFIG="$(canonicalize_config "$CONFIG")"
|
|
||||||
|
|
||||||
case "$CONFIG" in
|
case "$CONFIG" in
|
||||||
redbear-minimal)
|
redbear-full|redbear-mini|redbear-grub)
|
||||||
;;
|
|
||||||
redbear-live)
|
|
||||||
;;
|
|
||||||
redbear-live-mini)
|
|
||||||
;;
|
|
||||||
redbear-grub-live-mini)
|
|
||||||
;;
|
|
||||||
redbear-full)
|
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "ERROR: Unknown config '$CONFIG'"
|
echo "ERROR: Unknown config '$CONFIG'" >&2
|
||||||
echo "Supported: redbear-mini, redbear-full, redbear-live, redbear-live-mini, redbear-grub-live-mini"
|
echo "Supported: redbear-full, redbear-mini, redbear-grub" >&2
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
@@ -216,7 +175,6 @@ if [ "$APPLY_PATCHES" = "1" ]; then
|
|||||||
apply_patch_dir "$PROJECT_ROOT/local/patches/bootloader" "$PROJECT_ROOT/recipes/core/bootloader/source" "bootloader"
|
apply_patch_dir "$PROJECT_ROOT/local/patches/bootloader" "$PROJECT_ROOT/recipes/core/bootloader/source" "bootloader"
|
||||||
apply_patch_dir "$PROJECT_ROOT/local/patches/installer" "$PROJECT_ROOT/recipes/core/installer/source" "installer"
|
apply_patch_dir "$PROJECT_ROOT/local/patches/installer" "$PROJECT_ROOT/recipes/core/installer/source" "installer"
|
||||||
|
|
||||||
# repo cook can refetch nested sources when --upstream is enabled; keep relibc clean after patch application
|
|
||||||
stash_nested_repo_if_dirty "$PROJECT_ROOT/recipes/core/relibc/source" "relibc"
|
stash_nested_repo_if_dirty "$PROJECT_ROOT/recipes/core/relibc/source" "relibc"
|
||||||
echo ""
|
echo ""
|
||||||
fi
|
fi
|
||||||
@@ -232,12 +190,12 @@ if [ ! -f "target/release/repo" ]; then
|
|||||||
cargo build --release
|
cargo build --release
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$CONFIG" = "redbear-full" ] || [ "$CONFIG" = "redbear-live" ]; then
|
if [ "$CONFIG" = "redbear-full" ]; then
|
||||||
ensure_relibc_desktop_surface
|
ensure_relibc_desktop_surface
|
||||||
fi
|
fi
|
||||||
|
|
||||||
FW_AMD_DIR="$PROJECT_ROOT/local/firmware/amdgpu"
|
FW_AMD_DIR="$PROJECT_ROOT/local/firmware/amdgpu"
|
||||||
if [ "$CONFIG" != "redbear-minimal" ] && [ "$CONFIG" != "redbear-live-mini" ] && [ "$CONFIG" != "redbear-grub-live-mini" ]; then
|
if [ "$CONFIG" = "redbear-full" ]; then
|
||||||
if [ -d "$FW_AMD_DIR" ] && [ -n "$(ls -A "$FW_AMD_DIR" 2>/dev/null)" ]; then
|
if [ -d "$FW_AMD_DIR" ] && [ -n "$(ls -A "$FW_AMD_DIR" 2>/dev/null)" ]; then
|
||||||
FW_COUNT=$(ls "$FW_AMD_DIR"/*.bin 2>/dev/null | wc -l)
|
FW_COUNT=$(ls "$FW_AMD_DIR"/*.bin 2>/dev/null | wc -l)
|
||||||
echo ">>> Found $FW_COUNT AMD firmware blobs"
|
echo ">>> Found $FW_COUNT AMD firmware blobs"
|
||||||
@@ -268,38 +226,9 @@ echo "Image: build/$ARCH/$CONFIG/harddrive.img"
|
|||||||
echo ""
|
echo ""
|
||||||
echo "To run in QEMU:"
|
echo "To run in QEMU:"
|
||||||
echo " make qemu QEMUFLAGS=\"-m 4G\""
|
echo " make qemu QEMUFLAGS=\"-m 4G\""
|
||||||
if [ "$CONFIG" = "redbear-minimal" ] || [ "$CONFIG" = "redbear-desktop" ]; then
|
|
||||||
echo ""
|
|
||||||
echo "To validate the Phase 2 VM network baseline:"
|
|
||||||
echo " ./local/scripts/validate-vm-network-baseline.sh"
|
|
||||||
echo " ./local/scripts/test-vm-network-qemu.sh $CONFIG"
|
|
||||||
fi
|
|
||||||
if [ "$CONFIG" = "redbear-desktop" ] || [ "$CONFIG" = "redbear-full" ] || [ "$CONFIG" = "redbear-wayland" ] || [ "$CONFIG" = "redbear-kde" ]; then
|
|
||||||
echo ""
|
|
||||||
echo "To validate bounded low-level controller proofs:"
|
|
||||||
echo " ./local/scripts/test-lowlevel-controllers-qemu.sh $CONFIG"
|
|
||||||
echo " # or run individual checks: test-xhci-irq-qemu.sh, test-iommu-qemu.sh, test-ps2-qemu.sh, test-timer-qemu.sh"
|
|
||||||
echo ""
|
|
||||||
echo "To validate bounded USB maturity proofs:"
|
|
||||||
echo " ./local/scripts/test-usb-maturity-qemu.sh $CONFIG"
|
|
||||||
echo " # or run individual checks: test-usb-qemu.sh --check, test-usb-storage-qemu.sh"
|
|
||||||
fi
|
|
||||||
if [ "$CONFIG" = "redbear-wayland" ]; then
|
|
||||||
echo ""
|
|
||||||
echo "To validate the bounded Phase 4 Wayland runtime harness:"
|
|
||||||
echo " ./local/scripts/test-phase4-wayland-qemu.sh"
|
|
||||||
echo " # in guest: redbear-drm-display-check --vendor amd|intel"
|
|
||||||
fi
|
|
||||||
if [ "$CONFIG" = "redbear-kde" ]; then
|
|
||||||
echo ""
|
|
||||||
echo "To validate the primary KWin Wayland desktop path:"
|
|
||||||
echo " ./local/scripts/test-phase6-kde-qemu.sh --check"
|
|
||||||
echo " # in guest: redbear-drm-display-check --vendor amd|intel"
|
|
||||||
fi
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "To build live ISO:"
|
echo "To build live ISO:"
|
||||||
echo " make live CONFIG_NAME=$CONFIG"
|
echo " scripts/build-iso.sh $CONFIG"
|
||||||
echo " # live .iso outputs are for real bare metal, not VM/QEMU use"
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "To write a real bare-metal image to USB (verify device first!):"
|
echo "To write a real bare-metal image to USB (verify device first!):"
|
||||||
echo " dd if=build/$ARCH/$CONFIG/harddrive.img of=/dev/sdX bs=4M status=progress"
|
echo " dd if=build/$ARCH/$CONFIG/harddrive.img of=/dev/sdX bs=4M status=progress"
|
||||||
|
|||||||
@@ -226,16 +226,8 @@ echo ""
|
|||||||
|
|
||||||
section "Validating Red Bear configs..."
|
section "Validating Red Bear configs..."
|
||||||
declare -a redbear_configs=(
|
declare -a redbear_configs=(
|
||||||
"config/redbear-desktop.toml"
|
"config/redbear-mini.toml"
|
||||||
"config/redbear-minimal.toml"
|
|
||||||
"config/redbear-bluetooth-experimental.toml"
|
|
||||||
"config/redbear-full.toml"
|
"config/redbear-full.toml"
|
||||||
"config/redbear-wayland.toml"
|
|
||||||
"config/redbear-live.toml"
|
|
||||||
"config/redbear-live-mini.toml"
|
|
||||||
"config/redbear-live-full.toml"
|
|
||||||
"config/redbear-grub-live-mini.toml"
|
|
||||||
"config/redbear-grub-live-full.toml"
|
|
||||||
"config/redbear-grub.toml"
|
"config/redbear-grub.toml"
|
||||||
)
|
)
|
||||||
declare -a found_configs=()
|
declare -a found_configs=()
|
||||||
@@ -247,9 +239,9 @@ for config_path in "${redbear_configs[@]}"; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
if [ "${#found_configs[@]}" -gt 0 ]; then
|
if [ "${#found_configs[@]}" -gt 0 ]; then
|
||||||
status "Found Red Bear config(s): ${found_configs[*]}"
|
status "Found Red Bear target config(s): ${found_configs[*]}"
|
||||||
else
|
else
|
||||||
warn "No redbear config found in config/. Build may rely on a different config intentionally"
|
warn "No redbear target config found in config/"
|
||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ recipes/wip/
|
|||||||
|
|
||||||
## KDE STATUS
|
## KDE STATUS
|
||||||
|
|
||||||
- Older WIP KDE app notes here are stale relative to `local/recipes/kde/` and `config/redbear-kde.toml`
|
- Older WIP KDE app notes here are stale relative to `local/recipes/kde/` and `config/redbear-full.toml`
|
||||||
- See `docs/05-KDE-PLASMA-ON-REDOX.md` top-level status note plus `local/docs/QT6-PORT-STATUS.md` for current state
|
- See `docs/05-KDE-PLASMA-ON-REDOX.md` top-level status note plus `local/docs/QT6-PORT-STATUS.md` for current state
|
||||||
|
|
||||||
## CONVENTIONS
|
## CONVENTIONS
|
||||||
|
|||||||
+9
-42
@@ -2,57 +2,27 @@
|
|||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
CONFIG_NAME="redbear-live"
|
CONFIG_NAME="redbear-mini"
|
||||||
ARCH="x86_64"
|
ARCH="x86_64"
|
||||||
ALLOW_UPSTREAM=0
|
ALLOW_UPSTREAM=0
|
||||||
|
|
||||||
canonicalize_live_config() {
|
|
||||||
case "$1" in
|
|
||||||
redbear-live-full)
|
|
||||||
printf '%s\n' "redbear-live"
|
|
||||||
;;
|
|
||||||
redbear-live-mini-grub)
|
|
||||||
printf '%s\n' "redbear-grub-live-mini"
|
|
||||||
;;
|
|
||||||
redbear-live-full-grub)
|
|
||||||
printf '%s\n' "redbear-grub-live-full"
|
|
||||||
;;
|
|
||||||
redbear-grub-live-full)
|
|
||||||
printf '%s\n' "redbear-grub-live-full"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
printf '%s\n' "$1"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
Usage: $(basename "$0") [OPTIONS] [CONFIG_NAME] [ARCH]
|
Usage: $(basename "$0") [OPTIONS] [CONFIG_NAME] [ARCH]
|
||||||
|
|
||||||
Build a Red Bear OS live ISO for real bare metal.
|
Build a Red Bear OS live ISO for real bare metal.
|
||||||
|
|
||||||
Important:
|
|
||||||
Live .iso outputs are for bare-metal boot/install/recovery workflows.
|
|
||||||
They are not the virtual/QEMU target surface; use harddrive.img + make qemu for virtualization.
|
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
--upstream Allow Redox/upstream recipe source refresh during build
|
--upstream Allow Redox/upstream recipe source refresh during build
|
||||||
-h, --help Show this help
|
-h, --help Show this help
|
||||||
|
|
||||||
Supported live ISO targets:
|
Supported targets:
|
||||||
redbear-live Full live ISO (graphical greeter + text fallback)
|
redbear-full Full desktop ISO (Wayland + KDE + GPU drivers)
|
||||||
redbear-live-mini Text-only mini live ISO
|
redbear-mini Text-only ISO (default)
|
||||||
redbear-grub-live-mini Text-only mini live ISO with GRUB bootloader
|
redbear-grub Text-only ISO with GRUB boot manager
|
||||||
redbear-grub-live-full Full live ISO with GRUB bootloader
|
|
||||||
|
|
||||||
Legacy compatibility aliases:
|
|
||||||
redbear-live-full → redbear-live
|
|
||||||
redbear-live-mini-grub → redbear-grub-live-mini
|
|
||||||
redbear-live-full-grub → redbear-grub-live-full
|
|
||||||
|
|
||||||
Defaults:
|
Defaults:
|
||||||
CONFIG_NAME=redbear-live
|
CONFIG_NAME=redbear-mini
|
||||||
ARCH=x86_64
|
ARCH=x86_64
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
@@ -93,14 +63,12 @@ fi
|
|||||||
[ ${#POSITIONAL[@]} -ge 1 ] && CONFIG_NAME="${POSITIONAL[0]}"
|
[ ${#POSITIONAL[@]} -ge 1 ] && CONFIG_NAME="${POSITIONAL[0]}"
|
||||||
[ ${#POSITIONAL[@]} -ge 2 ] && ARCH="${POSITIONAL[1]}"
|
[ ${#POSITIONAL[@]} -ge 2 ] && ARCH="${POSITIONAL[1]}"
|
||||||
|
|
||||||
CONFIG_NAME="$(canonicalize_live_config "$CONFIG_NAME")"
|
|
||||||
|
|
||||||
case "$CONFIG_NAME" in
|
case "$CONFIG_NAME" in
|
||||||
redbear-live|redbear-live-mini|redbear-grub-live-mini|redbear-grub-live-full)
|
redbear-full|redbear-mini|redbear-grub)
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "ERROR: Unsupported live ISO target '$CONFIG_NAME'" >&2
|
echo "ERROR: Unsupported target '$CONFIG_NAME'" >&2
|
||||||
usage >&2
|
echo "Supported: redbear-full, redbear-mini, redbear-grub" >&2
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
@@ -122,4 +90,3 @@ fi
|
|||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Done: build/${ARCH}/${CONFIG_NAME}.iso"
|
echo "Done: build/${ARCH}/${CONFIG_NAME}.iso"
|
||||||
echo "Note: live .iso outputs are for real bare metal, not VM/QEMU use."
|
|
||||||
|
|||||||
Reference in New Issue
Block a user