From 9f2de2a0b103b18d7fd34b299f27620e304e78d5 Mon Sep 17 00:00:00 2001 From: vasilito Date: Mon, 3 Aug 2026 13:07:25 +0300 Subject: [PATCH] docs+build: correct version drift, mangled prose, and toolchain-version gaps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Docs: - Baseline was stated as 0.3.1 across the canonical set while the branch, Cat 0/1 crates and every Cat 2 fork are 0.3.2. AGENTS.md also cited a sources/redbear-0.3.1/ archive that does not exist; the only archive present is sources/redbear-0.1.0/. Versioning examples now match the forks as they actually stand (redoxfs/syscall 0.9.1, libredox 0.1.19). - Repaired 18 instances of 'immutable archived' across 8 documents, where a global find/replace had turned sync/synced/archived into that phrase and produced ungrammatical text ('never auto-immutable archived', '### Source immutable archived'). - Settled the apply-patches.sh contradiction empirically. Both sides were wrong: the GROSS WARNING blocks (x5) described it as routine patch-linking, and SCRIPT-BEHAVIOR-MATRIX.md said build-redbear.sh 'never invokes' it. It is invoked at build-redbear.sh:487, but only to auto-repair a failed verify-overlay-integrity.sh check. - Dropped the dangling reference to a local/AGENTS.md section 'NO OVERLAY-STYLE PATCHES — SCOPED POLICY' that does not exist. Build system: - mk/prefix.mk hardcoded 13.2.0 in the limits.h removal, which silently no-ops after a toolchain upgrade and leaves the conflicting header. Version-globbed. - Parameterized GCC_RECIPE so the from-source toolchain path is not pinned to gcc13. - The three cstdlib strtold seds were not idempotent -- the shipped GCC 13 toolchain carried that comment block 17 times from repeated 'make prefix' runs. Each is now guarded. --- AGENTS.md | 27 ++-- CONTRIBUTING.md | 2 +- README.md | 6 +- docs/06-BUILD-SYSTEM-SETUP.md | 4 +- docs/07-RED-BEAR-OS-IMPLEMENTATION-PLAN.md | 8 +- docs/README.md | 4 +- local/AGENTS.md | 49 +++--- local/docs/BUILD-SYSTEM.md | 4 +- local/docs/LOCAL-FORK-SUPREMACY-POLICY.md | 2 +- local/docs/PATCH-GOVERNANCE.md | 4 +- local/docs/SCRIPT-BEHAVIOR-MATRIX.md | 27 ++-- .../dbus-interfaces/redbear-notifications.md | 62 +++++++ local/docs/dbus-interfaces/redbear-polkit.md | 52 ++++++ .../docs/dbus-interfaces/redbear-sessiond.md | 152 ++++++++++++++++++ .../redbear-statusnotifierwatcher.md | 67 ++++++++ local/docs/dbus-interfaces/redbear-udisks.md | 103 ++++++++++++ local/docs/dbus-interfaces/redbear-upower.md | 111 +++++++++++++ .../redbear-accessibility.md | 50 ++++++ local/docs/operator-runbooks/redbear-btctl.md | 53 ++++++ local/docs/operator-runbooks/redbear-btusb.md | 34 ++++ local/docs/operator-runbooks/redbear-dnsd.md | 37 +++++ local/docs/operator-runbooks/redbear-ime.md | 54 +++++++ .../docs/operator-runbooks/redbear-keymapd.md | 55 +++++++ .../docs/operator-runbooks/redbear-polkit.md | 48 ++++++ mk/prefix.mk | 14 +- 25 files changed, 961 insertions(+), 68 deletions(-) create mode 100644 local/docs/dbus-interfaces/redbear-notifications.md create mode 100644 local/docs/dbus-interfaces/redbear-polkit.md create mode 100644 local/docs/dbus-interfaces/redbear-sessiond.md create mode 100644 local/docs/dbus-interfaces/redbear-statusnotifierwatcher.md create mode 100644 local/docs/dbus-interfaces/redbear-udisks.md create mode 100644 local/docs/dbus-interfaces/redbear-upower.md create mode 100644 local/docs/operator-runbooks/redbear-accessibility.md create mode 100644 local/docs/operator-runbooks/redbear-btctl.md create mode 100644 local/docs/operator-runbooks/redbear-btusb.md create mode 100644 local/docs/operator-runbooks/redbear-dnsd.md create mode 100644 local/docs/operator-runbooks/redbear-ime.md create mode 100644 local/docs/operator-runbooks/redbear-keymapd.md create mode 100644 local/docs/operator-runbooks/redbear-polkit.md diff --git a/AGENTS.md b/AGENTS.md index 98d92218a5..f0e399ba9a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,7 +8,7 @@ ## Canonical build — do NOT bypass > ⚠️ **GROSS WARNING — DO NOT run `repo cook`, `repo fetch`, or `make live` directly.** -> These bypass the canonical build pipeline (`apply-patches.sh` patch-linking + staleness handling + correct dependency ordering), which causes broken/missing patches and wasted rebuild time. **ALWAYS build via `./local/scripts/build-redbear.sh [--upstream] `** (or the documented `make` targets it drives). If you think you need a single-recipe cook, run the canonical wrapper — it does the right thing and is faster in the end. +> These bypass the canonical build pipeline — the concurrency lock, the dirty-source and fork-branch gates, prefix-staleness detection and rebuild, overlay-integrity verification (which auto-repairs recipe symlinks via `apply-patches.sh` when it fails), source-fingerprint tracking, and correct dependency ordering — which causes broken/missing patches and wasted rebuild time. **ALWAYS build via `./local/scripts/build-redbear.sh [--upstream] `** (or the documented `make` targets it drives). If you think you need a single-recipe cook, run the canonical wrapper — it does the right thing and is faster in the end. ## OVERVIEW @@ -17,7 +17,7 @@ into a bootable Redox image. Uses a Makefile + Rust "cookbook" tool + TOML confi Languages: Rust (core), C (ported packages), TOML (config), Make (build orchestration). RedBearOS is a **full fork** of Redox OS — based on frozen, archived source snapshots. -Sources are immutable and never auto-immutable archived from upstream. All changes are explicit, +Sources are immutable and are never auto-synced from upstream. All changes are explicit, human-initiated operations. Durable Red Bear state belongs in `local/patches/`, `local/recipes/`, `local/docs/`, and tracked Red Bear configs. @@ -39,8 +39,10 @@ No "this seems too heavy for mini". **When in doubt: KEEP IT AND FIX IT.** This rule exists because agents have repeatedly destroyed months of work by deciding packages were "unnecessary" and silently removing them during syncs and config changes. -The current baseline is **Red Bear OS 0.3.1** (Redox snapshot at build-system commit `f55acba68`). -All recipe sources are pinned and archived in `sources/redbear-0.1.0/`. +The current baseline is **Red Bear OS 0.3.2** (development branch `0.3.2`). +`sources/redbear-0.1.0/` (Redox snapshot at build-system commit `f55acba68`) is the last +frozen release archive and is **not** the current source of truth — the current branch builds +from the `local/sources//` forks. It is the only archive present in `sources/`. ## STRUCTURE @@ -608,15 +610,18 @@ Round 14). Git hook details are documented in `local/docs/RELEASE-BUMP-WORKFLOW. ### Offline-First By Default Red Bear OS is a **fork with frozen sources**. The cookbook tool defaults to -`COOKBOOK_OFFLINE=true` (changed from upstream Redox's `false`). Builds use archived -sources from `sources/redbear-0.3.1/` — no network access during compilation. +`COOKBOOK_OFFLINE=true` (changed from upstream Redox's `false`). Builds resolve sources +locally — from the `local/sources/` forks on a development branch, or from +`sources/redbear-/` in release mode — with no network access during compilation. +`sources/redbear-0.1.0/` is currently the only archive present. To allow online fetching for non-protected development recipes, use the `--upstream` flag: ```bash ./local/scripts/build-redbear.sh --upstream redbear-mini ``` -In release mode (`REDBEAR_RELEASE=0.3.1`), online fetching is **completely disabled** +In release mode (e.g. `REDBEAR_RELEASE=0.1.0`, matching an archive that exists under +`sources/`), online fetching is **completely disabled** even with `COOKBOOK_OFFLINE=false`. Sources are immutable in release mode. **For development with local forks** (see "LOCAL FORK MODEL" in `local/AGENTS.md`), @@ -690,7 +695,7 @@ Critical rules: After ANY change to patches or `recipe.toml`: > ⚠️ **GROSS WARNING — DO NOT run `repo cook`, `repo fetch`, or `make live` directly.** -> These bypass the canonical build pipeline (`apply-patches.sh` patch-linking + staleness handling + correct dependency ordering), which causes broken/missing patches and wasted rebuild time. **ALWAYS build via `./local/scripts/build-redbear.sh [--upstream] `** (or the documented `make` targets it drives). If you think you need a single-recipe cook, run the canonical wrapper — it does the right thing and is faster in the end. +> These bypass the canonical build pipeline — the concurrency lock, the dirty-source and fork-branch gates, prefix-staleness detection and rebuild, overlay-integrity verification (which auto-repairs recipe symlinks via `apply-patches.sh` when it fails), source-fingerprint tracking, and correct dependency ordering — which causes broken/missing patches and wasted rebuild time. **ALWAYS build via `./local/scripts/build-redbear.sh [--upstream] `** (or the documented `make` targets it drives). If you think you need a single-recipe cook, run the canonical wrapper — it does the right thing and is faster in the end. 1. Validate patches: `./target/release/repo validate-patches ` 2. Remove source: `rm -rf recipes/core//source` @@ -839,8 +844,10 @@ local/patches/ ### Release Model (Fork) -Red Bear OS is a full fork based on frozen Redox snapshots. Sources are immutable -and never auto-immutable archived. The current baseline is 0.3.1 (sources archive at sources/redbear-0.1.0/ is the LAST frozen release; current branch builds from local/sources/ forks). +Red Bear OS is a full fork based on frozen Redox snapshots. Sources are immutable and are +never refreshed from upstream automatically. The current baseline is 0.3.2; the archive at +`sources/redbear-0.1.0/` is the last frozen release, and the current branch builds from the +`local/sources/` forks. ```bash # Check for newer Redox snapshots (read-only, zero side effects): diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0d60838dcb..97765cc814 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -94,7 +94,7 @@ relibc, drivers, system utilities) live here as submodule branches or tracked tr - **Chat** — upstream Redox has [Matrix](https://matrix.to/#/#redox-join:matrix.org) and [Discord](https://discord.gg/JfggvrHGDY) rooms. Red Bear contributors are welcome there, but issue tracking happens on Gitea, not in chat. -- **Merge requests** — open MRs on Gitea against the `0.3.1` branch. Small MRs review faster +- **Merge requests** — open MRs on Gitea against the current release branch (`0.3.2`). Small MRs review faster than large ones; split big work into reviewable slices. --- diff --git a/README.md b/README.md index 1407de35e4..e690fda6a9 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,8 @@ ## What is Red Bear OS? Red Bear OS is a general-purpose, Unix-like operating system with a **microkernel architecture**, -written entirely in **Rust**. It is a full fork of Redox OS (baseline 0.3.1), actively developed -on branch `0.3.1` with hardware enablement, multiple filesystems, a native greeter and login +written entirely in **Rust**. It is a full fork of Redox OS (baseline 0.3.2), actively developed +on branch `0.3.2` with hardware enablement, multiple filesystems, a native greeter and login system, and a KDE Plasma desktop path. We aim to stay close to upstream Redox — diverging only where necessary to add missing @@ -118,7 +118,7 @@ make qemu Red Bear OS **boots to a login prompt** in QEMU with working wired networking, D-Bus system bus, hardware detection daemons, and three filesystem backends (RedoxFS, ext4, FAT). The ISO builds -successfully on branch `0.3.1`. Graphics packages are frozen at latest upstream stable +successfully on branch `0.3.2`. Graphics packages are frozen at latest upstream stable (Qt 6.11.1, KF6 6.27.0, Plasma 6.7.2, SDDM 0.21.0, Mesa 26.1.4, wayland-protocols 1.49). | Area | Status | diff --git a/docs/06-BUILD-SYSTEM-SETUP.md b/docs/06-BUILD-SYSTEM-SETUP.md index b7f0a41eff..560ea931f1 100644 --- a/docs/06-BUILD-SYSTEM-SETUP.md +++ b/docs/06-BUILD-SYSTEM-SETUP.md @@ -14,7 +14,7 @@ Build this repository using the Red Bear release fork model: -- sources are frozen, immutable release snapshots at baseline 0.3.1, +- sources are frozen, immutable release snapshots at baseline 0.3.2, - durable Red Bear state lives in `local/patches/`, `local/recipes/`, `local/docs/`, and tracked Red Bear configs, - build from archived sources offline by default; provision new releases explicitly via provision-release.sh. @@ -227,7 +227,7 @@ sudo dd if=build/x86_64/harddrive.img of=/dev/sdX bs=4M status=progress Under the Red Bear release fork model, remember: -- `recipes/*/source/` is an immutable archived release snapshot, +- `recipes/*/source/` is an immutable, archived release snapshot, - Red Bear-owned shipping deltas should be preserved under `local/patches/` and `local/recipes/`, - sources are built offline by default; provision new releases via provision-release.sh. diff --git a/docs/07-RED-BEAR-OS-IMPLEMENTATION-PLAN.md b/docs/07-RED-BEAR-OS-IMPLEMENTATION-PLAN.md index 3533f50641..deb29f5eba 100644 --- a/docs/07-RED-BEAR-OS-IMPLEMENTATION-PLAN.md +++ b/docs/07-RED-BEAR-OS-IMPLEMENTATION-PLAN.md @@ -29,18 +29,18 @@ relates to Debian. - Redox is upstream. - Red Bear carries integration, packaging, validation, and subsystem release fork on top. -- Upstream-owned source trees are immutable archived release snapshot. +- Upstream-owned source trees are immutable, archived release snapshots. - Durable Red Bear state belongs in `local/patches/`, `local/recipes/`, `local/docs/`, and tracked Red Bear configs. -The project is in the right long-term shape only when immutable archived upstream sources can be fetched, +The project is in the right long-term shape only when archived upstream sources can be fetched, Red Bear release fork can be apply, and the project still rebuilds successfully. ## Ownership Rules ### Upstream-owned layer -These are immutable archived release sources, not durable Red Bear storage: +These are immutable, archived release sources, not durable Red Bear storage: - `recipes/*/source/` - most of `recipes/` outside local release fork symlinks @@ -159,7 +159,7 @@ The current evidence-backed baseline is: - major local subsystem plans exist under `local/docs/`, - native wired networking is present, - Qt6 and major downstream desktop dependencies build, -- Wayland-facing relibc compatibility surfaces now rebuild from a immutable archived upstream relibc source +- Wayland-facing relibc compatibility surfaces now rebuild from an archived upstream relibc source tree via local patch carriers, - `libwayland` and `qtbase` build successfully from the reconstructed relibc state, - the Red Bear-native greeter/login path now has a bounded passing runtime proof, while broader KDE/KWin session stability is still not yet a general runtime claim, diff --git a/docs/README.md b/docs/README.md index 38b85fe437..b17cab6da4 100644 --- a/docs/README.md +++ b/docs/README.md @@ -21,11 +21,11 @@ current/canonical versus historical/reference split obvious. > **Repository model:** RedBearOS relates to Redox in the same way Ubuntu relates to Debian. > Upstream Redox remains the base platform; Red Bear carries packaging, patch, validation, and > subsystem release fork on top. For long-term stability, upstream-owned source trees should be treated -> as immutable archived release snapshot, while durable Red Bear state belongs in `local/patches/`, +> as immutable, archived release snapshots, while durable Red Bear state belongs in `local/patches/`, > `local/recipes/`, `local/docs/`, and tracked Red Bear configs. > > **WIP policy:** if an upstream recipe or subsystem is still marked WIP, Red Bear treats it as a -> local project until upstream promotes it to first-class status. We may immutable archived from upstream WIP, +> local project until upstream promotes it to first-class status. We may sync from upstream WIP, > but we should fix and ship from the Red Bear release fork until upstream support is real enough to > replace the local copy. diff --git a/local/AGENTS.md b/local/AGENTS.md index 92688b5cb1..94cea709aa 100644 --- a/local/AGENTS.md +++ b/local/AGENTS.md @@ -6,7 +6,7 @@ updates (`git pull` on the build system repo), this directory is untouched. ## Canonical build — do NOT bypass > ⚠️ **GROSS WARNING — DO NOT run `repo cook`, `repo fetch`, or `make live` directly.** -> These bypass the canonical build pipeline (`apply-patches.sh` patch-linking + staleness handling + correct dependency ordering), which causes broken/missing patches and wasted rebuild time. **ALWAYS build via `./local/scripts/build-redbear.sh [--upstream] `** (or the documented `make` targets it drives). If you think you need a single-recipe cook, run the canonical wrapper — it does the right thing and is faster in the end. +> These bypass the canonical build pipeline — the concurrency lock, the dirty-source and fork-branch gates, prefix-staleness detection and rebuild, overlay-integrity verification (which auto-repairs recipe symlinks via `apply-patches.sh` when it fails), source-fingerprint tracking, and correct dependency ordering — which causes broken/missing patches and wasted rebuild time. **ALWAYS build via `./local/scripts/build-redbear.sh [--upstream] `** (or the documented `make` targets it drives). If you think you need a single-recipe cook, run the canonical wrapper — it does the right thing and is faster in the end. ## STUB AND WORKAROUND POLICY — ZERO TOLERANCE @@ -41,9 +41,9 @@ files, Wayland protocol stubs, D-Bus service stubs, and any other layer of the s Red Bear OS is a **full fork** based on frozen Redox OS snapshots: - We baseline on a specific Redox OS state and work from immutable, archived sources - - The `local/` directory contains our custom work — untouched by any source immutable archived + - The `local/` directory contains our custom work — untouched by any source sync - First-class configs use `redbear-*` naming (not `my-*`, which is gitignored) - - Sources are NEVER auto-immutable archived from upstream — all changes are explicit, human-initiated + - Sources are NEVER auto-synced from upstream — all changes are explicit, human-initiated ## LOCAL FORK SUPREMACY POLICY (ABSOLUTE) @@ -173,7 +173,7 @@ The **only** branches that exist in the `RedBear-OS` repo are: | Branch type | Examples | Who creates them | |---|---|---| -| **Release branches** | `master`, `0.2.0`, `0.2.1`, …, `0.3.1`, … | **Operator only**, one per Red Bear OS release cycle. | +| **Release branches** | `master`, `0.2.0`, `0.2.1`, …, `0.3.1`, `0.3.2`, … | **Operator only**, one per Red Bear OS release cycle. | | **Submodule branches** | `submodule/base`, `submodule/kernel`, `submodule/relibc`, … (9 total) | **Operator only**, one per forked upstream component. | | **Recovery branches** | `recovered/quirks` | **Operator only**, for emergency recovery work. | @@ -187,7 +187,7 @@ Agents **MUST NOT**: explicitly decided to fork a new upstream component. **If you need to work on a change, commit to the branch you are already on.** -Release work goes on the current release branch (e.g. `0.3.1`). Fork changes +Release work goes on the current release branch (e.g. `0.3.2`). Fork changes go on the appropriate `submodule/` branch. There is no justification for a new branch — use a commit, a patch file, or a tracked tree instead. @@ -750,7 +750,7 @@ Red Bear OS has exactly two version categories: These are original Red Bear projects (tlc, cub, redbear-*, etc.) with no upstream. Their version **MUST** be the current Red Bear OS branch version -(e.g. `0.3.1` on branch `0.3.1`). +(e.g. `0.3.2` on branch `0.3.2`). **Category 2 (Cat 2) — Upstream Redox forks** (`local/sources/*/`): @@ -763,19 +763,20 @@ resolution while still marking the fork as Red Bear's: +rb ``` -For example, on branch `0.3.1`: -- `redoxfs` tracking upstream `0.9.0` → `version = "0.9.0+rb0.3.1"` -- `kernel` tracking upstream `0.5.12` → `version = "0.5.12+rb0.3.1"` -- `syscall` tracking upstream `0.9.0` → `version = "0.9.0+rb0.3.1"` +For example, on branch `0.3.2`: +- `redoxfs` tracking upstream `0.9.1` → `version = "0.9.1+rb0.3.2"` +- `kernel` tracking upstream `0.5.12` → `version = "0.5.12+rb0.3.2"` +- `syscall` tracking upstream `0.9.1` → `version = "0.9.1+rb0.3.2"` +- `libredox` tracking upstream `0.1.19` → `version = "0.1.19+rb0.3.2"` The `-rb` suffix MUST NOT be used in `Cargo.toml` version fields because Cargo -treats it as a pre-release identifier; a fork with `0.9.0-rb0.3.1` would not +treats it as a pre-release identifier; a fork with `0.9.1-rb0.3.2` would not satisfy upstream transitive dependency requirements such as `^0.9.0`. The `+rb` build-metadata suffix leaves the upstream version intact (`0.9.0`) so that `[patch.crates-io]` and transitive crates.io dependencies resolve correctly. -When the Red Bear OS branch changes (e.g. `0.3.1` → `0.2.6`), **all** Cat 2 -fork versions automatically bump their suffix: `0.9.0+rb0.3.1` → `0.9.0+rb0.2.6`. +When the Red Bear OS branch changes (e.g. `0.3.1` → `0.3.2`), **all** Cat 2 +fork versions automatically bump their suffix: `0.9.1+rb0.3.1` → `0.9.1+rb0.3.2`. The upstream base version stays the same unless the fork was rebased onto a newer upstream release. @@ -789,8 +790,8 @@ newer upstream release. ``` `sync-versions.sh` handles BOTH categories in one pass: -- Cat 1: sets `version = ""` (e.g. `0.3.1`) -- Cat 2: sets `version = "+rb"` (e.g. `0.9.0+rb0.3.1`) +- Cat 1: sets `version = ""` (e.g. `0.3.2`) +- Cat 2: sets `version = "+rb"` (e.g. `0.9.0+rb0.3.2`) The `--check` mode is suitable for CI gates and preflight checks. @@ -968,12 +969,12 @@ The `version = "X.Y.Z+rbB.B.B"` field in a Cat 2 fork's `Cargo.toml` MUST accura describe the underlying source code. Specifically: - The `` part (before `+rb`) **MUST be the upstream release tag** that the - source code is based on. Setting `version = "0.9.0+rb0.3.1"` on a fork whose + source code is based on. Setting `version = "0.9.0+rb0.3.2"` on a fork whose source code is actually upstream `0.8.x` (or any other version) is a **fake label** and a **policy violation**. The `+rbB.B.B` suffix is meaningful only when applied to the correct upstream base. - The `+rbB.B.B` part (after `+rb`) **MUST be the current Red Bear OS branch - version**. On branch `0.3.1`, every Cat 2 fork MUST use `+rb0.3.1`. This makes + version**. On branch `0.3.2`, every Cat 2 fork MUST use `+rb0.3.2`. This makes it trivial to trace which Red Bear branch a fork was built for. - The fork's source code **MUST be a real rebase onto upstream ``** plus Red Bear patches, NOT a mislabeled old version of the upstream code with the @@ -1006,7 +1007,7 @@ describe the underlying source code. Specifically: ``` local/sources/redoxfs/ -├── Cargo.toml # version = "0.9.0+rb0.3.1" (upstream 0.9.0 + branch 0.3.1) +├── Cargo.toml # version = "0.9.1+rb0.3.2" (upstream 0.9.1 + branch 0.3.2) ├── Cargo.toml.orig # mirrors upstream, regenerated for cargo consistency ├── src/... # the upstream 0.9.0 source tree, byte-for-byte └── local/patches/redoxfs/ # Red Bear patches, each one small and reviewable @@ -1022,14 +1023,14 @@ only difference from upstream — that would be a fake label. **What a fake label looks like (REJECTED):** -- A fork whose `Cargo.toml` says `0.9.0+rb0.3.1` but whose source content is +- A fork whose `Cargo.toml` says `0.9.0+rb0.3.2` but whose source content is upstream `0.8.6` (a different version). -- A fork whose `Cargo.toml` says `0.9.0+rb0.3.1` but whose dep constraints +- A fork whose `Cargo.toml` says `0.9.0+rb0.3.2` but whose dep constraints (`redox_syscall = "0.7.0"`, `libredox = "0.1.12"`, etc.) reference versions that don't match upstream 0.9.0's ecosystem. - A fork whose `+rb` suffix doesn't match the current branch (e.g. - `+rb0.2.4` while on branch `0.3.1`). -- A fork whose only commit is "fork: bump to +rb0.3.1 version suffix" with no + `+rb0.2.4` while on branch `0.3.2`). +- A fork whose only commit is "fork: bump to +rb0.3.2 version suffix" with no actual rebasing onto the matching upstream tag. All of these are caught by the enforcement script and the build aborts @@ -1342,7 +1343,7 @@ redox-master/ ← git pull updates mainline Redox ## HOW TO BUILD RED BEAR OS > ⚠️ **GROSS WARNING — DO NOT run `repo cook`, `repo fetch`, or `make live` directly.** -> These bypass the canonical build pipeline (`apply-patches.sh` patch-linking + staleness handling + correct dependency ordering), which causes broken/missing patches and wasted rebuild time. **ALWAYS build via `./local/scripts/build-redbear.sh [--upstream] `** (or the documented `make` targets it drives). If you think you need a single-recipe cook, run the canonical wrapper — it does the right thing and is faster in the end. +> These bypass the canonical build pipeline — the concurrency lock, the dirty-source and fork-branch gates, prefix-staleness detection and rebuild, overlay-integrity verification (which auto-repairs recipe symlinks via `apply-patches.sh` when it fails), source-fingerprint tracking, and correct dependency ordering — which causes broken/missing patches and wasted rebuild time. **ALWAYS build via `./local/scripts/build-redbear.sh [--upstream] `** (or the documented `make` targets it drives). If you think you need a single-recipe cook, run the canonical wrapper — it does the right thing and is faster in the end. ```bash # CANONICAL build command — produces a live ISO for bare metal @@ -1783,7 +1784,7 @@ See `local/docs/BUILD-SYSTEM-INVARIANTS.md` for invariants I1-I3. - **DO NOT** assume mainline recipe names won't conflict — prefix custom ones (e.g., `redox-`) - **DO NOT** use `my-*` naming for configs that should be tracked in git — use `redbear-*` instead - **DO NOT** edit config/base.toml directly — our configs include it and override via TOML merge -- **DO NOT** attempt to immutable archived sources from upstream — sources are immutable; use provision-release.sh +- **DO NOT** attempt to sync sources from upstream — sources are immutable; use provision-release.sh ## COMPREHENSIVE IMPLEMENTATION POLICY diff --git a/local/docs/BUILD-SYSTEM.md b/local/docs/BUILD-SYSTEM.md index e0ebea65e7..452436a29e 100644 --- a/local/docs/BUILD-SYSTEM.md +++ b/local/docs/BUILD-SYSTEM.md @@ -175,9 +175,9 @@ cooks the tree as-is. A read-only startup advisory reports any leftover `recipes//`. Version policy (`sync-versions.sh`): - **Cat 1** — in-house crates under `local/recipes/*/source/`: `version = ` - (e.g. `0.3.1`). + (e.g. `0.3.2`). - **Cat 2** — upstream forks under `local/sources/*/`: - `version = +rb` (e.g. `0.9.0+rb0.3.1`; `+rb` build + `version = +rb` (e.g. `0.9.0+rb0.3.2`; `+rb` build metadata, never `-rb`). - **Vendored upstream** under `local/recipes/` (e.g. `brush`, a Cargo workspace): keeps its **upstream** crate versions (internal `^` requirements). Mark it with diff --git a/local/docs/LOCAL-FORK-SUPREMACY-POLICY.md b/local/docs/LOCAL-FORK-SUPREMACY-POLICY.md index eb6c43772c..52b7f84ea9 100644 --- a/local/docs/LOCAL-FORK-SUPREMACY-POLICY.md +++ b/local/docs/LOCAL-FORK-SUPREMACY-POLICY.md @@ -23,7 +23,7 @@ of functionality our system needs, implemented in our tree, maintained by us. ### What Red Bear OS Is Red Bear OS is a **full fork** of Redox OS, based on frozen Redox snapshots -(currently branch `0.3.1`; legacy release archive at `sources/redbear-0.1.0/` +(currently branch `0.3.2`; legacy release archive at `sources/redbear-0.1.0/` at build-system commit `f55acba68`). We are NOT a downstream distributor of Redox. We are NOT a configuration overlay on top of Redox. diff --git a/local/docs/PATCH-GOVERNANCE.md b/local/docs/PATCH-GOVERNANCE.md index 822704c92d..8e01557c8d 100644 --- a/local/docs/PATCH-GOVERNANCE.md +++ b/local/docs/PATCH-GOVERNANCE.md @@ -57,7 +57,7 @@ When reordering patches, test the FULL chain: remove source, rebuild, verify. `recipes/core/base/recipe.toml` is git-tracked. Changes to it are durable. `recipes/core/base/source/` is a fetched working copy — destroyed by `make clean`, -`make distclean`, source immutable archived, and provision-release. +`make distclean`, source re-sync, and provision-release. Any change to source/ MUST be preserved as a patch in `local/patches/base/`. @@ -76,7 +76,7 @@ implemented work to bypass build failures. After ANY change to the patches list or patch files: > ⚠️ **GROSS WARNING — DO NOT run `repo cook`, `repo fetch`, or `make live` directly.** -> These bypass the canonical build pipeline (`apply-patches.sh` patch-linking + staleness handling + correct dependency ordering), which causes broken/missing patches and wasted rebuild time. **ALWAYS build via `./local/scripts/build-redbear.sh [--upstream] `** (or the documented `make` targets it drives). If you think you need a single-recipe cook, run the canonical wrapper — it does the right thing and is faster in the end. +> These bypass the canonical build pipeline — the concurrency lock, the dirty-source and fork-branch gates, prefix-staleness detection and rebuild, overlay-integrity verification (which auto-repairs recipe symlinks via `apply-patches.sh` when it fails), source-fingerprint tracking, and correct dependency ordering — which causes broken/missing patches and wasted rebuild time. **ALWAYS build via `./local/scripts/build-redbear.sh [--upstream] `** (or the documented `make` targets it drives). If you think you need a single-recipe cook, run the canonical wrapper — it does the right thing and is faster in the end. 1. Remove the source tree: `rm -rf recipes/core/base/source` 2. Full rebuild: `REDBEAR_ALLOW_PROTECTED_FETCH=1 CI=1 make r.base` diff --git a/local/docs/SCRIPT-BEHAVIOR-MATRIX.md b/local/docs/SCRIPT-BEHAVIOR-MATRIX.md index db46cba6f1..4eaa4ed60c 100644 --- a/local/docs/SCRIPT-BEHAVIOR-MATRIX.md +++ b/local/docs/SCRIPT-BEHAVIOR-MATRIX.md @@ -11,21 +11,20 @@ The goal is to remove guesswork from the sync/fetch/apply/build workflow. > The "release fork" in this document refers to Red Bear's owned code in > `local/sources/`, `local/recipes/`, `config/redbear-*.toml`, and > `local/patches//` (Rule 2 external patches for big external -> projects). There is **no overlay layer** of `apply-patches.sh`-style -> symlinks between `recipes/` and `local/recipes/`. See -> `local/AGENTS.md` "NO OVERLAY-STYLE PATCHES — SCOPED POLICY" for the -> two-rule model. Where this document references the historical -> `apply-patches.sh` script, that is **legacy/archived** behavior; the -> canonical build flow is `local/scripts/build-redbear.sh `, -> which never invokes `apply-patches.sh`. +> projects). The `recipes//` entries are symlinks into +> `local/recipes/`, and `apply-patches.sh` is what (re)creates them. It is no +> longer a routine build step: `build-redbear.sh` runs +> `verify-overlay-integrity.sh` and calls `apply-patches.sh` **only to +> auto-repair** when that check fails (`build-redbear.sh:487`). The canonical +> build flow is `local/scripts/build-redbear.sh `. ## Matrix | Script | Primary role | What it handles | What it does **not** guarantee | |---|---|---|---| | `local/scripts/provision-release.sh` | Refresh top-level upstream repo state | fetches upstream, reports conflict risk, rebases repo commits. Under v6.0 the "release fork reapplication" step is no longer needed because `local/sources/`, `local/recipes/`, and `local/patches//` already live in the main repo (Rule 1 + Rule 2). | does not automatically solve every subsystem release fork conflict; does not by itself make upstream WIP recipes safe shipping inputs | -| `local/scripts/apply-patches.sh` | **LEGACY / ARCHIVED** — historical overlay only | under v5.x, applied build-system patches and relinked recipe patch symlinks; under v6.0 this is a no-op for in-tree components (Rule 1 direct edits) and is replaced by `cookbook_apply_patches` for big external projects (Rule 2). See `local/AGENTS.md`. | do not invoke during a v6.0 build. The `local/scripts/build-redbear.sh ` canonical entry point never calls it. | -| `local/scripts/build-redbear.sh` | **Canonical build entry point** for Red Bear profiles | under v6.0 it does NOT call `apply-patches.sh` — the release fork is already in `local/`. It enforces: (1) local-over-WIP recipe priority, (2) overlay integrity verification, (3) dirty-source gate (refuses uncommitted fork edits unless `--allow-dirty`; it does NOT stash the tree), (4) firmware presence warning, (5) profile validation, (6) cookbook build if needed, (7) image build. Canonical reference: `BUILD-SYSTEM.md`. `--upstream` triggers explicit source immutable archived for non-protected recipes. **`--check-sweep` runs `cargo check` against the target triple on every fork + every config recipe BEFORE the cook/prefix cycle, surfacing all type/borrow errors at once.** | does not guarantee every nested upstream source tree is fresh; does not replace explicit subsystem/runtime validation | +| `local/scripts/apply-patches.sh` | **Overlay repair** — not a routine build step | under v5.x, applied build-system patches and relinked recipe patch symlinks; under v6.0 this is a no-op for in-tree components (Rule 1 direct edits) and is replaced by `cookbook_apply_patches` for big external projects (Rule 2). See `local/AGENTS.md`. | do not invoke by hand during a normal build. `build-redbear.sh` calls it automatically, and only when `verify-overlay-integrity.sh` fails. | +| `local/scripts/build-redbear.sh` | **Canonical build entry point** for Red Bear profiles | under v6.0 it calls `apply-patches.sh` only to auto-repair a failed overlay-integrity check, not as a routine patch-linking step. It enforces: (1) local-over-WIP recipe priority, (2) overlay integrity verification, (3) dirty-source gate (refuses uncommitted fork edits unless `--allow-dirty`; it does NOT stash the tree), (4) firmware presence warning, (5) profile validation, (6) cookbook build if needed, (7) image build. Canonical reference: `BUILD-SYSTEM.md`. `--upstream` triggers an explicit source sync for non-protected recipes. **`--check-sweep` runs `cargo check` against the target triple on every fork + every config recipe BEFORE the cook/prefix cycle, surfacing all type/borrow errors at once.** | does not guarantee every nested upstream source tree is fresh; does not replace explicit subsystem/runtime validation | | `scripts/fetch-all-sources.sh` | Fetch mainline recipe source inputs for builds | downloads mainline/upstream recipe sources, reports status/preflight, and supports config-scoped fetches while leaving local release fork in place | does not mean fetched upstream WIP source is the durable shipping source of truth | | `local/scripts/fetch-sources.sh` | Fetch mainline recipe sources for browsing and patching | when passed `--upstream`, fetches `recipes/*` source trees so the upstream-managed side is locally available for reading, editing, and patch preparation | does not decide whether upstream should replace the local release fork | | `local/scripts/build-redbear-wifictl-redox.sh` | Build `redbear-wifictl` for the Redox target with the repo toolchain | prepends `prefix/x86_64-unknown-redox/sysroot/bin` to `PATH` and runs `cargo build --target x86_64-unknown-redox` in the `redbear-wifictl` crate | does not prove runtime Wi-Fi behavior; only closes the target-build environment gap for this crate | @@ -116,7 +115,7 @@ all failures are listed in a single run. Default Red Bear behavior is local-first: - use locally available package/source trees and release fork state for normal builds, -- treat upstream immutable archived as an explicit operator action only (`--upstream`, dedicated fetch/sync), +- treat an upstream sync as an explicit operator action only (`--upstream`, dedicated fetch/sync), - do not fail policy-level expectations just because upstream network access is temporarily broken. This is required so builds and recovery workflows remain operable during upstream outages or @@ -124,7 +123,7 @@ connectivity failures. ### Upstream sync -Use `local/scripts/provision-release.sh` when the goal is to immutable archived the top-level upstream Redox base. +Use `local/scripts/provision-release.sh` when the goal is to sync the top-level upstream Redox base. This is a repository sync operation, not a guarantee that every local subsystem release fork is already rebased cleanly. @@ -150,12 +149,12 @@ This is the core durable-state recovery path, not a normal build step. Use `local/scripts/build-redbear.sh` when the goal is to build a tracked Red Bear profile from the current upstream base plus local release fork. Add `--upstream` only when you explicitly want Redox/upstream -recipe sources immutable archived during that build. +recipe sources synced during that build. -### Source immutable archived +### Source sync Use `scripts/fetch-all-sources.sh` and `local/scripts/fetch-sources.sh --upstream` when the goal is to -immutable archived recipe source inputs, but do not confuse fetched upstream WIP source with a trusted shipping +sync recipe source inputs, but do not confuse fetched upstream WIP source with a trusted shipping source. ## WIP Rule in Script Terms diff --git a/local/docs/dbus-interfaces/redbear-notifications.md b/local/docs/dbus-interfaces/redbear-notifications.md new file mode 100644 index 0000000000..63090de0d8 --- /dev/null +++ b/local/docs/dbus-interfaces/redbear-notifications.md @@ -0,0 +1,62 @@ +# redbear-notifications — D-Bus Interface + +**Bus:** session +**Well-known name:** `org.freedesktop.Notifications` +**Object paths:** +- `/org/freedesktop/Notifications` — Notifications server + +## Interface: `org.freedesktop.Notifications` + +### Methods + +| Method | Signature | Description | +|--------|-----------|-------------| +| `Notify` | `(app_name: s, replaces_id: u, app_icon: s, summary: s, body: s, actions: as, hints: a{sv}, expire_timeout: i) → (u)` | Create or replace a notification. Returns notification ID. If `replaces_id` is non-zero and matches an existing notification owned by the same sender, the record is updated in-place. Maximum 1024 active notifications. | +| `CloseNotification` | `(id: u) → ()` | Close a notification by ID. Emits `NotificationClosed` signal with reason 3 (closed). | +| `GetCapabilities` | `() → (as)` | Returns `["body", "body-markup"]` | +| `GetServerInformation` | `() → (ssss)` | Returns `("Red Bear Notifications", "redbear", "0.3.1", "1.2")` | +| `InvokeAction` | `(id: u, action_key: s) → ()` | Invoke an action on a notification. Validates: (1) caller is the notification owner, (2) the action key was declared at notify time. Emits `ActionInvoked` signal, then removes the notification. | + +### Properties + +| Property | Type | Description | +|----------|------|-------------| +| `Idle` | `b` | Always `false` (idle tracking not implemented) | + +### Signals + +| Signal | Signature | Description | +|--------|-----------|-------------| +| `NotificationClosed` | `(id: u, reason: u)` | A notification was closed. Reason: 1=expired, 2=dismissed, 3=closed. | +| `ActionInvoked` | `(id: u, action_key: s)` | An action was invoked on a notification. | + +## Notification Lifecycle + +1. **Creation** (`Notify`): A notification record is stored with owner (sender bus name), action keys, expire timeout, and issue timestamp. Monotonically increasing IDs starting from 1. If `replaces_id` matches an existing record, that record is updated; otherwise a new record is created. + +2. **Expiry** (background sweeper, 500 ms interval): Notifications with `expire_timeout > 0` are checked against `issued_at + expire_timeout`. Expired notifications are removed and `NotificationClosed(1)` is emitted. Notifications with `expire_timeout <= 0` never expire. + +3. **Action invocation** (`InvokeAction`): Validates sender ownership and action key. Emits `ActionInvoked`, then removes the notification and emits `NotificationClosed(2)`. + +4. **Close** (`CloseNotification`): Removes the notification and emits `NotificationClosed(3)`. + +5. **Sender vanishing** (background reaper, 2 s interval): Every 2 seconds, the daemon queries `org.freedesktop.DBus.NameHasOwner` for each tracked sender. If a sender has vanished from the bus, all its notifications are removed and `NotificationClosed(2)` is emitted for each. + +6. **Bound enforcement**: When the active notification count exceeds 1024, the oldest notification (by insertion order) is evicted and `NotificationClosed(2)` is emitted. + +## Action Format + +The `actions` parameter is a flat string array of alternating key-label pairs: +``` +["default", "Open", "reply", "Reply"] +``` +The daemon extracts keys (every even-indexed element) and validates `InvokeAction` against them. + +## Connection + +- Session bus (`ConnectionBuilder::session()`) +- Registers well-known name `org.freedesktop.Notifications` on the session bus + +## References +- [Desktop Notifications Specification](https://specifications.freedesktop.org/notification-spec/notification-spec-latest.html) v1.2 +- Conformance: Full Notify/CloseNotification/GetCapabilities/GetServerInformation. Action invocation with ownership validation. Expiry sweeper. Sender reaper for vanished bus names. Bounded notification store (1024 max). No persistence across restarts. No sound/image/hint processing beyond storage. No idle tracking. diff --git a/local/docs/dbus-interfaces/redbear-polkit.md b/local/docs/dbus-interfaces/redbear-polkit.md new file mode 100644 index 0000000000..37a0013eb6 --- /dev/null +++ b/local/docs/dbus-interfaces/redbear-polkit.md @@ -0,0 +1,52 @@ +# redbear-polkit — D-Bus Interface + +**Bus:** system +**Well-known name:** `org.freedesktop.PolicyKit1` +**Object paths:** +- `/org/freedesktop/PolicyKit1/Authority` — Authority object + +## Interface: `org.freedesktop.PolicyKit1.Authority` + +### Methods + +| Method | Signature | Description | +|--------|-----------|-------------| +| `CheckAuthorization` | `(subject_kind: s, subject: a{sv}, action_id: s, details: a{sv}, flags: u, cancellation_id: s) → (b, b, a{sv})` | Check if a subject is authorized for an action. Returns `(authorized, is_challenge, details)`. The subject dictionary must contain `uid` (U32 or I32). UID 0 (root) is always authorized. Other UIDs are checked against the policy file. | +| `RegisterAuthenticationAgent` | `(session: (s, o), locale: s, object_path: s) → ()` | No-op stub (authentication agents are not supported) | +| `UnregisterAuthenticationAgent` | `(session: (s, o), object_path: s) → ()` | No-op stub | +| `EnumerateActions` | `(locale: s) → (a(sssssu(a{sv})))` | Returns empty list (action enumeration not implemented) | + +### Properties + +| Property | Type | Description | +|----------|------|-------------| +| `BackendName` | `s` | `"redbear-uid-policy"` (const) | +| `BackendVersion` | `s` | `"0.2.0"` (const) | + +### Authorization Decision Logic + +1. Extract UID from subject dictionary (field `uid`, accepts U32 and I32 types) +2. If UID is 0 → authorized (root bypass) +3. Look up action ID in the TOML policy file (`/etc/polkit-1/policy.toml` or `REDBEAR_POLKIT_POLICY`) +4. Evaluate user specs on the matching line, left to right: + - `*` → match any user + - `N` (decimal integer) → match specific UID + - `@group` → match if UID is a member of the named group + - `!spec` → explicit deny +5. Explicit deny overrides any explicit allow +6. Unknown action → denied by default + +### Subject Format + +The `subject` dictionary is a `HashMap`. Supported fields: +- `uid` (u32 or i32): The UID to authorize. Required. + +The `subject_kind` string (e.g. `"unix-user"` or `"unix-process"`) is logged but not used for authorization decisions — only the `uid` field matters. + +### Details Format + +The `details` dictionary (third return value) is always empty. The upstream spec allows backends to return additional key-value pairs; Red Bear's implementation returns an empty `HashMap`. + +## References +- [PolicyKit D-Bus API](https://www.freedesktop.org/software/polkit/docs/latest/ref-dbus-api.html) +- Conformance: Minimal implementation. `CheckAuthorization` with UID-based policy file evaluation. No authentication agent support (Register/Unregister are no-ops). No action enumeration. No JavaScript rules.d support. Backend is a simple TOML key-value store. diff --git a/local/docs/dbus-interfaces/redbear-sessiond.md b/local/docs/dbus-interfaces/redbear-sessiond.md new file mode 100644 index 0000000000..8a21156b5b --- /dev/null +++ b/local/docs/dbus-interfaces/redbear-sessiond.md @@ -0,0 +1,152 @@ +# redbear-sessiond — D-Bus Interface + +**Bus:** system +**Well-known name:** `org.freedesktop.login1` +**Object paths:** +- `/org/freedesktop/login1` — Manager object (main entry point) +- `/org/freedesktop/login1/session/c1` — Session object +- `/org/freedesktop/login1/seat/seat0` — Seat object +- `/org/freedesktop/login1/user/current` — User object + +## Interface: `org.freedesktop.login1.Manager` + +### Methods + +| Method | Signature | Description | +|--------|-----------|-------------| +| `GetSession` | `(id: s) → (o)` | Returns object path for session by ID | +| `GetSessionByPID` | `(pid: u) → (o)` | Returns object path for session owning PID (stub: returns c1) | +| `ListSessions` | `() → (a(susso))` | List all sessions: `[(id, uid, user, seat, object_path)]` | +| `GetSeat` | `(id: s) → (o)` | Returns object path for seat by ID | +| `ListSeats` | `() → (a(so))` | List all seats: `[(id, object_path)]` | +| `GetUser` | `(uid: u) → (o)` | Returns object path for user by UID | +| `GetUserByPID` | `(pid: u) → (o)` | Returns object path for user owning PID (stub: returns current) | +| `ListUsers` | `() → (a(uso))` | List all users: `[(uid, name, object_path)]` | +| `ListInhibitors` | `() → (a(ssssuu))` | List all registered inhibitors | +| `Inhibit` | `(what: s, who: s, why: s, mode: s) → (h)` | Register a shutdown/sleep inhibitor; returns pipe FD. The inhibitor is tracked by sender bus name; removal occurs on FD close or sender vanishing | +| `PowerOff` | `(interactive: b) → ()` | Shut down the system. Writes `\n` to `/scheme/acpi/shutdown`. Emits `PrepareForShutdown(true)` before and `PrepareForShutdown(false)` after. | +| `Reboot` | `(interactive: b) → ()` | Reboot the system. Writes `\n` to `/scheme/acpi/reboot`. Emits `PrepareForShutdown(true)` before. | +| `Suspend` | `(interactive: b) → ()` | Suspend the system. Emits `PrepareForSleep(true)` before and `PrepareForSleep(false)` after. | +| `CanPowerOff` | `() → (s)` | Returns `"yes"`, `"no"`, or `"challenge"` (always `"yes"` when `/scheme/acpi/shutdown` is writable) | +| `CanReboot` | `() → (s)` | Returns `"yes"`, `"no"`, or `"challenge"` | +| `CanSuspend` | `() → (s)` | Returns `"yes"`, `"no"`, or `"challenge"` (stub: always `"no"`) | +| `CanHibernate` | `() → (s)` | Stub: always `"no"` | +| `CanHybridSleep` | `() → (s)` | Stub: always `"no"` | +| `CanSuspendThenHibernate` | `() → (s)` | Stub: always `"no"` | +| `CanSleep` | `() → (s)` | Aggregate: `"yes"` if any sleep state is available | +| `ActivateSession` | `(session_id: s) → ()` | Mark session as active | +| `ActivateSessionOnSeat` | `(session_id: s, seat_id: s) → ()` | Activate session on specific seat | +| `LockSession` | `(session_id: s) → ()` | Lock a specific session | +| `UnlockSession` | `(session_id: s) → ()` | Unlock a specific session | +| `LockSessions` | `() → ()` | Lock all sessions | +| `UnlockSessions` | `() → ()` | Unlock all sessions | +| `TerminateSession` | `(session_id: s) → ()` | Terminate a specific session | +| `TerminateUser` | `(uid: u) → ()` | Terminate all sessions for a user | +| `KillSession` | `(session_id: s, who: s, signal_number: i) → ()` | Send signal to session leader | +| `KillUser` | `(uid: u, signal_number: i) → ()` | Send signal to user session leader | + +### Properties + +| Property | Type | Description | +|----------|------|-------------| +| `IdleHint` | `b` | Whether the seat has been idle for the configured timeout | +| `IdleSinceHint` | `t` | CLOCK_REALTIME timestamp of last activity | +| `IdleSinceHintMonotonic` | `t` | CLOCK_MONOTONIC timestamp of last activity | +| `BlockInhibited` | `s` | Colon-separated list of `who:why` for block-mode inhibitors | +| `DelayInhibited` | `s` | Colon-separated list of `who:why` for delay-mode inhibitors | +| `InhibitDelayMaxUSec` | `t` | Maximum delay before forced shutdown (5 s default) | +| `HandleLidSwitch` | `s` | Lid switch policy: `"ignore"` (default) | +| `HandlePowerKey` | `s` | Power key policy: `"poweroff"` (default) | +| `PreparingForShutdown` | `b` | Whether a shutdown operation is in progress | +| `PreparingForSleep` | `b` | Whether a sleep operation is in progress | + +### Signals + +| Signal | Signature | Description | +|--------|-----------|-------------| +| `SeatNew` | `(id: s, path: o)` | A new seat was added | +| `SeatRemoved` | `(id: s, path: o)` | A seat was removed | +| `PrepareForShutdown` | `(active: b)` | Shutdown is about to begin / has completed | +| `PrepareForSleep` | `(active: b)` | Sleep is about to begin / has completed | + +## Interface: `org.freedesktop.login1.Session` + +### Methods + +| Method | Signature | Description | +|--------|-----------|-------------| +| `Activate` | `() → ()` | Activate this session | +| `TakeControl` | `(force: b) → ()` | Take control of the session | +| `ReleaseControl` | `() → ()` | Release session control | +| `TakeDevice` | `(major: u, minor: u) → (h)` | Take a device (returns FD). Emits `PauseDevice` signal. | +| `ReleaseDevice` | `(major: u, minor: u) → ()` | Release a previously-taken device. Emits `ResumeDevice` signal. | +| `PauseDeviceComplete` | `(major: u, minor: u) → ()` | Signal that device pause is complete | +| `SetIdleHint` | `(idle: b) → ()` | Set the session idle state | +| `SetLockedHint` | `(locked: b) → ()` | Set the session lock state | +| `SetType` | `(type: s) → ()` | Set the session type (e.g. `"wayland"`) | +| `Terminate` | `() → ()` | Terminate this session | +| `Kill` | `(who: s, signal_number: i) → ()` | Send signal to session process | + +### Properties + +| Property | Type | Description | +|----------|------|-------------| +| `Active` | `b` | Whether this session is currently active | +| `Remote` | `b` | Whether this is a remote session (always false) | + +### Signals + +| Signal | Signature | Description | +|--------|-----------|-------------| +| `PauseDevice` | `(major: u, minor: u, type: s)` | A device is being paused | +| `ResumeDevice` | `(major: u, minor: u, fd: h)` | A device is being resumed (FD re-opened) | + +## Interface: `org.freedesktop.login1.Seat` + +### Methods + +| Method | Signature | Description | +|--------|-----------|-------------| +| `SwitchTo` | `(vt: u) → ()` | Switch to virtual terminal | + +### Properties + +| Property | Type | Description | +|----------|------|-------------| +| `Id` | `s` | Seat identifier (default: `"seat0"`) | +| `ActiveSession` | `(s, o)` | Active session ID and object path | +| `Sessions` | `a(so)` | List of sessions on this seat | +| `CanGraphical` | `b` | Whether this seat supports graphical sessions (always `true`) | +| `CanTTY` | `b` | Whether this seat supports TTY sessions (always `true`) | +| `IdleHint` | `b` | Whether this seat is idle | + +## Runtime State + +The daemon maintains a `SharedRuntime` (RwLock-protected) with: +- `seat_id`: current seat identifier +- `session_id`: current session identifier +- `uid`: current user UID +- `user_name`: current user name +- `display`: current display number +- `vt`: current virtual terminal +- `session_type`: session type string +- `inhibitors`: list of registered inhibitors with sender tracking +- `last_activity`: monotonic timestamp + +## AC adapter / power events + +The `acpi_watcher` background task: +- Reads `/sys/class/power_supply/ACAD/online` every 2 s (or `/sys/class/power_supply/AC*/online`) +- Emits `PropertyChanged` on `org.freedesktop.login1.Manager` when the AC state transitions +- Transitions are debounced: an event is only emitted when the state actually changes + +## Connection + +- Uses zbus `ConnectionBuilder` with the system bus address from `DBUS_STARTER_ADDRESS` or `DBUS_SYSTEM_BUS_ADDRESS` (default: `unix:path=/run/dbus/system_bus_socket`) +- Waits up to 30 s for the D-Bus socket, polling multiple candidate paths +- Retries connection 3 times with 1 s backoff (first attempt failure is silent — normal when D-Bus SASL auth is not yet ready) +- Exposes a UNIX control socket at `/run/redbear-sessiond/control` for out-of-band commands (e.g. `reload`) + +## References +- [systemd-logind D-Bus API](https://www.freedesktop.org/wiki/Software/systemd/logind/) +- Conformance: Subset-compatible. Implements the login1 Manager, Session, and Seat interfaces. Inhibitor tracking with FD-polling reaper. Power/sleep operations via ACPI scheme. No user session tracking beyond a single "current" user. No multi-seat support. Device take/release with PauseDevice/ResumeDevice signal contract. diff --git a/local/docs/dbus-interfaces/redbear-statusnotifierwatcher.md b/local/docs/dbus-interfaces/redbear-statusnotifierwatcher.md new file mode 100644 index 0000000000..d20a5a2c2a --- /dev/null +++ b/local/docs/dbus-interfaces/redbear-statusnotifierwatcher.md @@ -0,0 +1,67 @@ +# redbear-statusnotifierwatcher — D-Bus Interface + +**Bus:** session +**Well-known name:** `org.kde.StatusNotifierWatcher` +**Object paths:** +- `/StatusNotifierWatcher` — Watcher object + +## Interface: `org.kde.StatusNotifierWatcher` + +### Methods + +| Method | Signature | Description | +|--------|-----------|-------------| +| `RegisterStatusNotifierItem` | `(item: s) → ()` | Register a status notifier item. The `item` parameter is either a full object path (e.g. `/org/example/Item`) or a bus name (e.g. `:1.42` or `org.example.App`). Object paths from different senders are deduplicated by prepending the sender's unique bus name. Emits `StatusNotifierItemRegistered`. | +| `UnregisterStatusNotifierItem` | `(item: s) → ()` | Unregister a previously-registered item. Only the original owning sender can unregister. Emits `StatusNotifierItemUnregistered`. | +| `RegisterStatusNotifierHost` | `(host: s) → ()` | Register a status notifier host (typically the system tray panel). Emits `StatusNotifierHostRegistered`. | +| `UnregisterStatusNotifierHost` | `(host: s) → ()` | Unregister a status notifier host. Only the original owning sender can unregister. | + +### Properties + +| Property | Type | Description | +|----------|------|-------------| +| `RegisteredStatusNotifierItems` | `as` | Read-only list of registered item bus names/paths | +| `IsStatusNotifierHostRegistered` | `b` | Read-only: true if at least one host is registered | +| `ProtocolVersion` | `i` | Always `0` (per KDE spec) | + +### Signals + +| Signal | Signature | Description | +|--------|-----------|-------------| +| `StatusNotifierItemRegistered` | `(service: s)` | A new status notifier item was registered | +| `StatusNotifierItemUnregistered` | `(service: s)` | A status notifier item was unregistered | +| `StatusNotifierHostRegistered` | `() → ()` | A new status notifier host was registered | +| `StatusNotifierHostUnregistered` | `() → ()` | A status notifier host was unregistered | + +## Ownership and Deduplication + +- Each registration is owned by the caller's unique bus name (from the D-Bus message header). +- Object paths (values starting with `/`) are namespaced by sender: `:1.42/StatusNotifierItem` is distinct from `:1.99/StatusNotifierItem`. The display value (via `RegisteredStatusNotifierItems` property and signals) strips the owner prefix. +- Bus names (values not starting with `/`) are treated as-is — the first registration wins. +- Only the owning sender can unregister its own entries. Calling `Unregister` with the wrong sender is a silent no-op. +- Maximum 1024 entries per registry (items and hosts independently bounded). Oldest-first eviction when full. + +## NameOwnerChanged Listener + +A background task subscribes to `org.freedesktop.DBus.NameOwnerChanged` signals on the session bus. When a unique bus name (starting with `:`) releases its bus name (new owner is empty), all items and hosts owned by that sender are purged and the appropriate unregistration signals are emitted. + +Well-known name releases (e.g. `org.example.App` losing its bus name) do NOT trigger automatic purge — only unique name (`:1.N`) releases do. This matches KDE spec behavior. + +## Input Validation + +All registration values are validated: +- Must be non-empty +- Maximum length 256 characters +- Must not contain NUL or other control characters (including C0/C1 control codes and Unicode format chars) +- Invalid values are rejected with `org.freedesktop.DBus.Error.InvalidArgs` + +## Connection + +- Session bus (`ConnectionBuilder::session()`) +- Waits up to 6 s for `DBUS_SESSION_BUS_ADDRESS` env var to be set (30 polls at 200 ms) +- Registers well-known name on session bus +- SIGTERM/Ctrl-C handler for clean shutdown + +## References +- [KDE StatusNotifierItem Specification](https://www.freedesktop.org/wiki/Specifications/StatusNotifierItem/) +- Conformance: Full StatusNotifierWatcher implementation. Owner-keyed item/host tracking with canonical deduplication. NameOwnerChanged-based auto-purge for vanished unique bus names. Bounded registries with deterministic eviction. Input validation. All four registration/unregistration methods, three properties, and all four signals. diff --git a/local/docs/dbus-interfaces/redbear-udisks.md b/local/docs/dbus-interfaces/redbear-udisks.md new file mode 100644 index 0000000000..e43cfd1bfb --- /dev/null +++ b/local/docs/dbus-interfaces/redbear-udisks.md @@ -0,0 +1,103 @@ +# redbear-udisks — D-Bus Interface + +**Bus:** system +**Well-known name:** `org.freedesktop.UDisks2` +**Object paths:** +- `/org/freedesktop/UDisks2` — ObjectManager root +- `/org/freedesktop/UDisks2/Manager` — Manager object +- `/org/freedesktop/UDisks2/drives/` — Per-drive objects +- `/org/freedesktop/UDisks2/block_devices/` — Per-block objects + +## Interface: `org.freedesktop.DBus.ObjectManager` + +At `/org/freedesktop/UDisks2`: + +| Method | Signature | Description | +|--------|-----------|-------------| +| `GetManagedObjects` | `() → (a{oa{sa{sv}}})` | Return all managed objects with their interfaces and properties | + +| Signal | Signature | Description | +|--------|-----------|-------------| +| `InterfacesAdded` | `(o, a{sa{sv}})` | New interfaces appeared on an object path | +| `InterfacesRemoved` | `(o, as)` | Interfaces were removed from an object path | + +## Interface: `org.freedesktop.UDisks2.Manager` + +### Methods + +| Method | Signature | Description | +|--------|-----------|-------------| +| `GetBlockDevices` | `(options: a{sv}) → (ao)` | List all block device object paths | +| `GetDrives` | `(options: a{sv}) → (ao)` | List all drive object paths | + +### Properties + +| Property | Type | Description | +|----------|------|-------------| +| `Version` | `s` | Package version (from `CARGO_PKG_VERSION`) | +| `SupportedFilesystems` | `as` | Currently empty (filesystem support detects at mount time) | +| `SupportedEncryptionTypes` | `as` | Empty (encryption not supported) | +| `DefaultEncryptionType` | `s` | Empty | + +## Interface: `org.freedesktop.UDisks2.Drive` + +### Methods + +None (property-only interface). + +### Properties + +| Property | Type | Description | +|----------|------|-------------| +| `ConnectionBus` | `s` | Scheme identity string (e.g. `"scheme:ahci"`, `"scheme:nvme"`) | +| `Size` | `t` | Total drive size in bytes | + +## Interface: `org.freedesktop.UDisks2.Block` + +### Methods + +| Method | Signature | Description | +|--------|-----------|-------------| +| `Mount` | `(options: a{sv}) → (s)` | Mount the block device. Accepts `fstype` option (`"ext4"` or `"vfat"`). Auto-detects ext4 (magic 0xEF53 at offset 0x438) and FAT (magic 0x4D44 at end of VBR). Returns mount point path. | +| `Unmount` | `(options: a{sv}) → ()` | Unmount a previously-mounted block device. Sends SIGTERM to the child filesystem daemon. | + +### Properties + +| Property | Type | Description | +|----------|------|-------------| +| `Device` | `ay` | Device path as byte array | +| `PreferredDevice` | `ay` | Preferred device path (same as Device) | +| `Symlinks` | `aay` | Empty (no symlink tracking) | +| `Size` | `t` | Block device size in bytes | +| `ReadOnly` | `b` | Whether the device is read-only | +| `Drive` | `o` | Parent drive object path | +| `HintPartitionable` | `b` | Whether the block is a partitionable device | +| `MountPoints` | `aay` | Current mount points (empty when not mounted) | +| `IdType` | `s` | Detected filesystem type: `"ext4"`, `"vfat"`, or `""` (unknown) | + +## Inventory Discovery + +At startup, `Inventory::scan()` enumerates block devices from: +- `/scheme/diskd/` — disk aggregator scheme (BlockDev entries) +- `/scheme/ahci/` — AHCI scheme +- `/scheme/nvme/` — NVMe scheme + +Each device is classified as a `DriveDevice` with associated `BlockDevice` entries. Object paths are stable (derived from the device name). + +## Filesystem Detection + +`detect_filesystem(device_path)` reads the block device: +1. Offset 0x438: ext4 magic (`0xEF53` at bytes 56-57 of superblock) +2. End of VBR: FAT magic (`0x4D44` signature at VBR tail) + +If `fstype` is passed as a mount option, it takes precedence over detection. + +## Connection + +- System bus, same `DBUS_STARTER_ADDRESS` / `DBUS_SYSTEM_BUS_ADDRESS` env var resolution as other D-Bus daemons +- 3 retry attempts at 1 s intervals +- SIGTERM/Ctrl-C handler for clean shutdown + +## References +- [UDisks2 D-Bus API](https://udisks.freedesktop.org/docs/latest/ref-dbus.html) +- Conformance: Subset implementation. Drive and Block objects with static properties. Mount/Unmount with ext4 and FAT support. ObjectManager for discovery. No ATA, partition table, filesystem size, or SMART interfaces. No encryption, RAID, or loop support. diff --git a/local/docs/dbus-interfaces/redbear-upower.md b/local/docs/dbus-interfaces/redbear-upower.md new file mode 100644 index 0000000000..5ecee37a0e --- /dev/null +++ b/local/docs/dbus-interfaces/redbear-upower.md @@ -0,0 +1,111 @@ +# redbear-upower — D-Bus Interface + +**Bus:** system +**Well-known name:** `org.freedesktop.UPower` +**Object paths:** +- `/org/freedesktop/UPower` — UPower daemon root +- `/org/freedesktop/UPower/devices/DisplayDevice` — Composite display device +- `/org/freedesktop/UPower/devices/line_power_` — Per-adapter AC power devices +- `/org/freedesktop/UPower/devices/battery_` — Per-battery devices + +## Interface: `org.freedesktop.UPower` + +### Methods + +| Method | Signature | Description | +|--------|-----------|-------------| +| `EnumerateDevices` | `() → (ao)` | List all device object paths | +| `GetCriticalAction` | `() → (s)` | Returns `"PowerOff"` | + +### Properties + +| Property | Type | Description | +|----------|------|-------------| +| `DaemonVersion` | `s` | `"0.1.0"` (const) | +| `OnBattery` | `b` | Whether running on battery (no AC adapters online and at least one battery discharging). Computed from snapshot. | + +### Signals + +| Signal | Signature | Description | +|--------|-----------|-------------| +| `Changed` | `()` | Power state changed (emitted on poll interval or ACPI notification) | + +## Interface: `org.freedesktop.UPower.Device` + +### Methods + +None (property-only interface). + +### Properties (all devices) + +| Property | Type | Description | +|----------|------|-------------| +| `Type` | `u` | Device kind: 0=unknown, 1=line power, 2=battery | +| `State` | `u` | Device state: 0=unknown, 1=charging, 2=discharging, 3=empty, 4=fully charged | +| `Percentage` | `d` | Battery percentage (0.0–100.0). 0.0 for adapters, average across batteries for DisplayDevice | +| `IsPresent` | `b` | Whether the device hardware is present | +| `Online` | `b` | True for AC adapters that are plugged in; false for batteries | +| `NativePath` | `s` | ACPI scheme path (e.g. `/scheme/acpi/power/adapters/ACAD`) | +| `TimeToFull` | `x` | Seconds until fully charged (0 if not charging) | +| `TimeToEmpty` | `x` | Seconds until empty (0 if not discharging) | +| `Energy` | `d` | Current energy in Wh | +| `EnergyRate` | `d` | Present power draw in W (positive=discharging, negative=charging) | +| `BatteryLevel` | `u` | Higher-level battery status: 0=unknown, 3=normal, 4=low, 5=critical, 7=full | +| `PowerSupply` | `b` | Whether the device supplies power (true for online adapters, false for batteries) | +| `Serial` | `s` | Hardware serial identifier | + +### DisplayDevice properties + +The DisplayDevice at `/org/freedesktop/UPower/devices/DisplayDevice` is a composite view: +- `Type`: `DEVICE_KIND_BATTERY` if at least one battery exists, else `DEVICE_KIND_UNKNOWN` +- `State`: Aggregate state across all batteries (charging if any battery charging, discharging if any battery discharging) +- `Percentage`: Average of all battery percentages +- `IsPresent`: True if at least one battery exists +- `Online`: Always false + +## State Discovery + +At startup, `PowerRuntime::discover()` reads: +- `/scheme/acpi/power/adapters/` — lists subdirectories, each an AC adapter +- `/scheme/acpi/power/batteries/` — lists subdirectories, each a battery + +For each adapter: +- `path` — native ACPI path +- `online` — `u64`, non-zero means plugged in + +For each battery: +- `path` — native ACPI path +- `state` — `u64` bitmask (bit 0=discharging, bit 1=charging, bit 2=critical) +- `percentage` — `f64`, percentage charge +- `energy` — `f64`, energy in Wh +- `energy_rate` — `f64`, power in W +- `time_to_full` — `f64`, seconds +- `time_to_empty` — `f64`, seconds +- `serial` — hardware serial string + +## State Change Detection + +Two mechanisms: +1. **Poll interval:** Every 30 seconds (`POLL_INTERVAL_SECS`), take a snapshot and compare with the last. If the state changed, emit `Changed` signal. +2. **ACPI notification drain:** Every 250 ms (`NOTIFICATION_POLL_MS`), read `/scheme/acpi/notifications`. If notifications are present and the state changed, emit `Changed` signal. This reduces battery state change latency from 30 s to sub-second for ACPI-aware hardware. + +## Battery Level Mapping + +| Condition | Level | +|-----------|-------| +| State bit 0x4 (critical) set | `BATTERY_LEVEL_CRITICAL` (5) | +| Percentage < 10.0 | `BATTERY_LEVEL_CRITICAL` (5) | +| 10.0 ≤ Percentage < 25.0 | `BATTERY_LEVEL_LOW` (4) | +| Percentage ≥ 100.0 | `BATTERY_LEVEL_FULL` (7) | +| 25.0 ≤ Percentage < 100.0 | `BATTERY_LEVEL_NORMAL` (3) | +| Percentage unavailable | `BATTERY_LEVEL_UNKNOWN` (0) | + +## Connection + +- System bus, same env var resolution as other D-Bus daemons +- 3 retry attempts at 1 s intervals +- If `/scheme/acpi/power` is unavailable, serves an empty provisional UPower surface (no devices, daemon still registers on bus) + +## References +- [UPower D-Bus API](https://upower.freedesktop.org/docs/ref-dbus.html) +- Conformance: Subset implementation. Device enumeration from ACPI power scheme. Composite DisplayDevice. Changed signal on state transitions. No history/statistics. No Wakeups API. No suspend/hibernate integration (handled by login1). No backlight control. diff --git a/local/docs/operator-runbooks/redbear-accessibility.md b/local/docs/operator-runbooks/redbear-accessibility.md new file mode 100644 index 0000000000..bb64cb8866 --- /dev/null +++ b/local/docs/operator-runbooks/redbear-accessibility.md @@ -0,0 +1,50 @@ +# redbear-accessibility — Operator Runbook + +**Daemon:** redbear-accessibility +**Init service:** `/usr/lib/init.d/60_accessibility.service` +**Status check:** `cat /scheme/accessibility/status` +**Restart:** `init-svc restart accessibility` + +## Logs +- Destination: `stderr` (tagged `[accessibility]`) +- No env-var log level control; all messages are `INFO` or `ERROR` level. To increase verbosity, modify `src/main.rs:log_msg` calls. + +## Scheme +- **Scheme name:** `accessibility` +- **Root:** `/scheme/accessibility/` (directory, mode 0555) + +## Scheme Paths +| Path | Type | Mode | Description | +|------|------|------|-------------| +| `config` | file | 0644 | Read/write accessibility config (`key=value` lines) | +| `status` | file | 0644 | Read-only runtime status summary | +| `sticky-keys` | file | 0644 | Read active sticky modifiers; write `key [now_ms]` to feed input | + +## Config Properties (read/write via `config`) +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| `sticky_keys` | bool | false | Enable sticky key modifier latching | +| `slow_keys` | bool | false | Enforce minimum key press duration | +| `slow_key_delay_ms` | u64 | 300 | Minimum press duration for slow keys | +| `bounce_keys` | bool | false | Debounce rapid double-presses | +| `bounce_key_delay_ms` | u64 | 300 | Minimum interval between presses | +| `repeat_keys` | bool | true | Enable key repeat | +| `repeat_delay_ms` | u64 | 500 | Delay before repeat starts | + +## Sticky Key Modifier Scan Codes +| Code | Modifier | +|------|----------| +| 0x1D, 0x61, 0x64 | Ctrl | +| 0x2A, 0x36 | Shift | +| 0x38 | Alt | +| 0x5B, 0x5C | Meta (Super) | + +## Signals / SIGTERM Behavior +- No SIGTERM handler. Scheme socket close triggers clean exit. Registered via `register_sync_scheme`. + +## Common Issues +1. **`failed to register scheme:accessibility`** — Another daemon already registered the scheme name, or the scheme socket could not be created. Check for duplicate instances. +2. **Sticky keys not working** — Verify `sticky_keys=true` in config (`cat /scheme/accessibility/config`). The daemon must receive key events via `write` to `sticky-keys` (format: `key [now_ms]`). Passive — not auto-fed by the input stack yet. +3. **Bounce/slow key filtering too aggressive** — Adjust `slow_key_delay_ms` and `bounce_key_delay_ms` via config write. Increase values for users with tremors, decrease for fast typists. +4. **Config changes not persisting** — Config is in-memory only. No persistence to disk. Re-apply config via init service `[[files]]` entries or a startup script that writes to `/scheme/accessibility/config`. +5. **Root listing returns empty** — The root directory listing is hardcoded (`config\nstatus\nsticky-keys\n`). If `getdents` returns unexpected results, check that the caller uses correct Redox scheme I/O conventions. diff --git a/local/docs/operator-runbooks/redbear-btctl.md b/local/docs/operator-runbooks/redbear-btctl.md new file mode 100644 index 0000000000..bfb2e9ab63 --- /dev/null +++ b/local/docs/operator-runbooks/redbear-btctl.md @@ -0,0 +1,53 @@ +# redbear-btctl — Operator Runbook + +**Daemon:** redbear-btctl +**Init service:** `/usr/lib/init.d/21_btctl.service` +**Status check:** `redbear-btctl --status [adapter]` +**Restart:** `init-svc restart btctl` + +## Logs +- Destination: `stderr` (visible via `journalctl -u btctl`) +- Debug: `REDBEAR_BTCTL_LOG=debug redbear-btctl [command]` +- Trace: `REDBEAR_BTCTL_LOG=trace redbear-btctl [command]` + +## Modes +- CLI commands (one-shot): `--probe`, `--status`, `--scan`, `--bond-list`, `--bond-add-stub`, `--bond-remove`, `--connect`, `--disconnect`, `--read-char` +- Daemon mode (no args, Redox only): Long-running `scheme:btctl` daemon. Handles connect/disconnect/read-char via scheme write paths. On Redox host, CLI commands (`--connect`, `--disconnect`, `--read-char`) forward requests to the live daemon via `scheme:btctl` paths. + +## CLI Commands +| Command | Usage | Description | +|---------|-------|-------------| +| `--probe` | `redbear-btctl --probe` | Adapter list + capabilities | +| `--status` | `redbear-btctl --status [hciN]` | Adapter status, bond count, scan result count | +| `--scan` | `redbear-btctl --scan [hciN]` | Trigger stub scan (returns `demo-beacon,demo-sensor`) | +| `--bond-list` | `redbear-btctl --bond-list [hciN]` | List persisted bond records | +| `--bond-add-stub` | `redbear-btctl --bond-add-stub hci0 AA:BB:CC:DD:EE:FF [alias]` | Add stub bond record | +| `--bond-remove` | `redbear-btctl --bond-remove hci0 AA:BB:CC:DD:EE:FF` | Remove bond record | +| `--connect` | `redbear-btctl --connect hci0 AA:BB:CC:DD:EE:FF` | Connect to bonded device | +| `--disconnect` | `redbear-btctl --disconnect hci0 AA:BB:CC:DD:EE:FF` | Disconnect bonded device | +| `--read-char` | `redbear-btctl --read-char hci0 AA:BB:CC:DD:EE:FF ` | Read GATT characteristic | + +## Backend Selection +- `REDBEAR_BTCTL_BACKEND=stub` (default) — Stub backend with hardcoded adapter `hci0` +- `REDBEAR_BTCTL_BACKEND=hci` — Live HCI backend (reads from /scheme/btusb) + +## Scheme Paths (Daemon Mode, Redox Only) +- `/scheme/btctl/adapters//status` — Connection status +- `/scheme/btctl/adapters//transport-status` — Transport health +- `/scheme/btctl/adapters//connection-state` — Connected bond IDs +- `/scheme/btctl/adapters//connect` — Write bond ID to connect +- `/scheme/btctl/adapters//disconnect` — Write bond ID to disconnect +- `/scheme/btctl/adapters//read-char` — Write bond/service/char UUIDs to read +- `/scheme/btctl/adapters//connect-result` — Last connect result +- `/scheme/btctl/adapters//disconnect-result` — Last disconnect result +- `/scheme/btctl/adapters//read-char-result` — Last read-char result + +## Signals / SIGTERM Behavior +- No SIGTERM handler; killed by init system. Daemon uses `INIT_NOTIFY` fd for scheme-ready notification. + +## Common Issues +1. **`redbear-btctl daemon is not serving scheme:btctl`** — CLI command attempted a scheme write on a host without the daemon running. Start the daemon first (`redbear-btctl` with no args on Redox), or use the stub CLI path on the host (connect/disconnect/read-char output is marked `runtime_scope=process-local-host-cli`). +2. **`bond record not found`** — Bond must be created via `--bond-add-stub` before `--connect`/`--disconnect`/`--read-char`. Bonds persist to `bond_store_root` on disk. +3. **`explicit-startup-required` in status** — Transport runtime (`redbear-btusb --daemon`) is not running or its status file is missing/stale. The control daemon requires the USB transport layer to be active. +4. **`only the experimental` error on `--read-char`** — The stub backend only supports reading the Battery Service (0x180F) Battery Level (0x2A19) characteristic. Other UUIDs are rejected with this message. +5. **Stub backend limitation** — All commands produce bounded stub responses suitable for development/testing. Real hardware requires `REDBEAR_BTCTL_BACKEND=hci` with a live `redbear-btusb` daemon serving the USB transport. diff --git a/local/docs/operator-runbooks/redbear-btusb.md b/local/docs/operator-runbooks/redbear-btusb.md new file mode 100644 index 0000000000..a543a9eeb0 --- /dev/null +++ b/local/docs/operator-runbooks/redbear-btusb.md @@ -0,0 +1,34 @@ +# redbear-btusb — Operator Runbook + +**Daemon:** redbear-btusb +**Init service:** `/usr/lib/init.d/20_btusb.service` +**Status check:** `redbear-btusb --status` +**Restart:** `init-svc restart btusb` + +## Logs +- Destination: `stderr` (visible via `journalctl -u btusb`) +- Debug: `RUST_LOG=debug redbear-btusb --daemon` +- Trace: `RUST_LOG=trace redbear-btusb --daemon` + +## Modes +- `redbear-btusb --probe` — One-shot USB bus scan for Bluetooth adapters. Prints `adapters=`, `transport=usb`, `mode=ble-first`, adapter endpoint detail lines. +- `redbear-btusb --status` — Reads `/var/run/redbear-btusb/status` (90 s freshness window). Prints `runtime_visibility`, `daemon_status`, `controller_state`, `bd_address`, `hci_version`. +- `redbear-btusb --daemon` (default, no args) — Long-running daemon. Scans `/scheme/usb/` for Bluetooth adapters (USB class 0xE0, subclass 0x01; known-vendor fallback for Intel 0x8087, Realtek 0x0BDA, Broadcom 0x0A5C, CSR 0x0A12). Runs HCI init sequence (Reset → Read BD Addr → Read Local Version) on first adapter. Registers `scheme:btusb` via `redox_scheme::Socket`. + +## Runtime State Query +- Adapter enumeration: `cat /scheme/btusb/adapters` (or read from probe output) +- Controller info: `cat /var/run/redbear-btusb/status` + - `controller_state` = `closed | initializing | active | error` + - `bd_address`, `hci_version`, `hci_revision`, `manufacturer` + - `init_error` (present when state is `error`) +- USB probe raw: `redbear-btusb --probe` (parses `/scheme/usb` tree) + +## Signals / SIGTERM Behavior +- No SIGTERM handler. The init system kills the process directly. The status file at `/var/run/redbear-btusb/status` is cleaned up on normal exit via `Drop`. + +## Common Issues +1. **No adapters found** — Verify USB controller is up (`ls /scheme/usb`). Check USB descriptors exist at `/scheme/usb///descriptors`. The daemon probes only USB class 0xE0 subclass 0x01 devices, plus known-vendor fallback (vendor IDs 0x8087, 0x0BDA, 0x0A5C, 0x0A12). Non-Bluetooth-class devices from unknown vendors are invisible. +2. **`controller_state=error` with `init_error`** — HCI init sequence failed. Common causes: USB transport is closed, HCI Reset timed out (no event endpoint interrupt), malformed endpoint descriptors (missing interrupt IN, bulk IN, or bulk OUT). +3. **Intel CNVi (0x8087) init failure** — Intel firmware setup (`btintel::intel_setup_firmware`) is non-fatal. The `log::warn!` message means standard HCI init will still be attempted. Check `/var/run/redbear-btusb/status` for the resulting controller state. +4. **Stale status file** — Status files older than 90 seconds (`STATUS_FRESHNESS_SECS`) are treated as invalid; `--status` will return `runtime_visibility=installed-only` and `daemon_status=inactive`. +5. **`ENOENT` on scheme paths** — The daemon must be running (`redbear-btusb --daemon`) for `scheme:btusb` to exist. After `setrens(0, 0)`, the scheme is isolated in a null namespace. diff --git a/local/docs/operator-runbooks/redbear-dnsd.md b/local/docs/operator-runbooks/redbear-dnsd.md new file mode 100644 index 0000000000..df2c12c707 --- /dev/null +++ b/local/docs/operator-runbooks/redbear-dnsd.md @@ -0,0 +1,37 @@ +# redbear-dnsd — Operator Runbook + +**Daemon:** redbear-dnsd +**Init service:** `/usr/lib/init.d/30_dnsd.service` +**Status check:** `cat /scheme/dns` (scheme reachability), `ls /scheme/dns/resolv` (forwarder status) +**Restart:** `init-svc restart dnsd` + +## Logs +- Destination: `stderr` (visible via `journalctl -u dnsd`) +- Debug: `REDBEAR_DNSD_LOG=debug redbear-dnsd` +- Trace: `REDBEAR_DNSD_LOG=trace redbear-dnsd` + +## Architecture +- **Scheme:** `/scheme/dns` — FSScheme for DNS resolution +- **Loopback listener:** UDP port 53 on 127.0.0.1 — standard resolver port for relibc +- **mDNS responder:** Background thread, sends multicast DNS responses for the local hostname +- **netcfg nameserver subscription:** Watches `/scheme/netcfg/resolv/nameserver` for upstream DNS server changes (DHCP renewal) + +## Runtime State Query +- Upstream nameserver: `cat /scheme/netcfg/resolv/nameserver` +- Hostname: `cat /etc/hostname` +- Cache state: Internal in-memory `DnsCache` + `NegativeCache` (not exposed via scheme yet) +- Forwarder config: Defaults to `8.8.8.8`; overridden by netcfg nameserver at startup + +## Signals / SIGTERM Behavior +- No SIGTERM handler. Daemon uses `INIT_NOTIFY` fd for scheme-ready notification. On socket close, daemon exits cleanly. + +## Cache +- **DnsCache**: Positive responses cached with TTL-based expiry +- **NegativeCache**: NXDOMAIN responses cached with SOA MINIMUM TTL + +## Common Issues +1. **Relibc can't resolve hostnames** — Verify loopback listener started (`dnsd: loopback DNS listener on 127.0.0.1:53` in logs). If missing, UDP bind may have failed. Ensure `/scheme/dns` scheme is registered. +2. **No upstream resolution** — Check netcfg nameserver: `cat /scheme/netcfg/resolv/nameserver`. If empty, the daemon falls back to the hardcoded default (`8.8.8.8`). Ensure network is up. +3. **`cannot open /scheme/netcfg/resolv/nameserver for subscription`** — netcfg scheme not available; the daemon will use its default upstream servers. Upstream changes from DHCP renewals won't be detected. +4. **mDNS not responding** — The mDNS responder runs in a background thread. Check logs for bind errors. The hostname defaults to `redbear` if `/etc/hostname` is missing. +5. **Loopback send failures** — If the loopback thread logs `send_to(...) failed`, the DNS client (relibc) may have closed its socket before a response was ready. Transient on slow upstream lookups. diff --git a/local/docs/operator-runbooks/redbear-ime.md b/local/docs/operator-runbooks/redbear-ime.md new file mode 100644 index 0000000000..f32189d0bd --- /dev/null +++ b/local/docs/operator-runbooks/redbear-ime.md @@ -0,0 +1,54 @@ +# redbear-ime — Operator Runbook + +**Daemon:** redbear-ime +**Init service:** `/usr/lib/init.d/61_ime.service` +**Status check:** `cat /scheme/ime/state` +**Restart:** `init-svc restart ime` + +## Logs +- Destination: `stderr` (tagged `[ime]`) +- No env-var log level control; all messages are `INFO` or `ERROR` level. + +## Scheme +- **Scheme name:** `ime` +- **Root:** `/scheme/ime/` (directory, mode 0555) + +## Scheme Paths +| Path | Type | Mode | Description | +|------|------|------|-------------| +| `state` | file | 0644 | Read-only: `composing=`, `preedit=`, `committed=` | +| `compose` | file | 0644 | Write: feed key events (`feed [shift] [altgr]`) or `reset` to clear state | +| `candidates` | file | 0644 | Read-only: tab-separated compose candidate list | + +## Compose Engine +- **Current engine:** `BasicLatinEngine` (hardcoded, no config selection yet) +- **Dead key trigger:** Scancode 0x5D (apps/menu key). Cycles through grave, acute, circumflex, diaeresis, caron dead keys. +- **Compose table:** Supports à/è/ì/ò/ù (grave), á/é/í/ó/ú (acute), â/ê/î/ô/û (circumflex), ä/ë/ï/ö/ü (diaeresis), ǎ/ě/ǐ/ǒ/ǔ (caron). +- **US QWERTY layout:** Hardcoded scancode-to-char mapping in `BasicLatinEngine::scancode_to_char` + +## Writing to `compose` +``` +# Feed a key press (scancode, pressed, shift, altgr) +feed 0x1E 1 0 0 # 'a' press +feed 0x1E 0 0 0 # 'a' release + +# Feed a shift-modified key +feed 0x1E 1 1 0 # 'A' press + +# Feed a dead key sequence +feed 0x5D 1 0 0 # dead key toggle (grave) +feed 0x12 1 0 0 # 'e' → 'è' + +# Reset compose state +reset +``` + +## Signals / SIGTERM Behavior +- No SIGTERM handler. Scheme socket close triggers clean exit. Registered via `register_sync_scheme`. + +## Common Issues +1. **`failed to register scheme:ime`** — Another daemon already registered the scheme name. Kill the existing instance first. +2. **Dead key compose not working** — The compose key is scancode 0x5D (apps/menu). Ensure the input stack sends this scancode. The engine cycles through 5 dead key types (grave/acute/circumflex/diaeresis/caron) — press the compose key multiple times to select the desired accent. +3. **Committed text not appearing** — Read `/scheme/ime/state` to verify `committed=` has the expected character. The daemon accumulates committed output in memory; the compositor must read `state` to retrieve it. +4. **`BasicLatinEngine` is the only engine** — No engine selection mechanism exists. Latin-based scripts only (ASCII + Latin-1 Supplement composed characters). CJK, Indic, Arabic, etc. are not supported in the current `BasicLatinEngine`. +5. **Key releases (pressed=0) do nothing** — The engine only processes key presses (`pressed=1`). Always send both press and release events for compatibility with future engines that may track press duration. diff --git a/local/docs/operator-runbooks/redbear-keymapd.md b/local/docs/operator-runbooks/redbear-keymapd.md new file mode 100644 index 0000000000..6dc56472be --- /dev/null +++ b/local/docs/operator-runbooks/redbear-keymapd.md @@ -0,0 +1,55 @@ +# redbear-keymapd — Operator Runbook + +**Daemon:** redbear-keymapd +**Init service:** `/usr/lib/init.d/62_keymapd.service` +**Status check:** `cat /scheme/keymap/active` +**Restart:** `init-svc restart keymapd` + +## Logs +- Destination: `stderr` (tagged `[keymapd]`) +- No env-var log level control; all messages are `INFO` or `ERROR` level. Keymap load success/failure is logged at startup. + +## Scheme +- **Scheme name:** `keymap` +- **Root:** `/scheme/keymap/` (directory, mode 0555) + +## Scheme Paths +| Path | Type | Mode | Description | +|------|------|------|-------------| +| `active` | file | 0644 | R/W: current keymap name. Read returns `name=`. Write a keymap name to switch. | +| `list` | file | 0644 | Read-only: newline-separated list of available keymap names | +| `keymap/` | file | 0644 | Read-only: per-keymap detail (entries, compose, dead_keys, sample codepoints) | +| `set/` | action | — | Open this path to activate keymap `` (alternative to writing `active`) | + +## Built-in Keymaps (always available) +| Name | Description | +|------|-------------| +| `us` | US QWERTY (default) | +| `gb` | UK QWERTY | +| `dvorak` | Dvorak simplified layout | +| `azerty` | French AZERTY | +| `bepo` | French Bépo ergonomic layout | +| `it` | Italian QWERTY | + +## Configuration +- **`KEYMAP_DIR`** — Directory to scan for JSON keymap files (default: `/etc/keymaps`) +- **`XKB_CONFIG_ROOT`** — xkbcommon XKB data directory (e.g. `/usr/share/X11/xkb`). If set, the daemon loads an XKB keymap. +- **`XKB_DEFAULT_LAYOUT`** — XKB layout name (default: `us`) +- **`XKB_DEFAULT_VARIANT`** — Optional XKB variant (e.g. `dvorak`, `intl`) + +## JSON Keymap Format +Keymap files in `KEYMAP_DIR` must have `.json` extension. The daemon calls `Keymap::from_json(&name, &json_str)` to parse each file. The JSON format is documented in `keymap.rs`. + +## Scancode Translation +- `translate(scancode: u8, shift: bool, altgr: bool) -> char` +- Sample: `cat /scheme/keymap/active` shows `sample_scancode_30=` (scancode 0x1E = 'a' key, unshifted) + +## Signals / SIGTERM Behavior +- No SIGTERM handler. Scheme socket close triggers clean exit. Registered via `register_sync_scheme`. + +## Common Issues +1. **`failed to register scheme:keymap`** — Another daemon already registered the scheme name. +2. **`failed to load keymaps from `** — The directory does not exist or contains invalid JSON. Check file permissions and JSON syntax. The error is non-fatal; built-in keymaps are always available. +3. **XKB keymap not loading** — Requires `XKB_CONFIG_ROOT` to point at a valid xkbcommon data tree. The daemon calls `xkb::load_xkb_keymap()` which reads `keycodes/`, `symbols/`, `types/`, `compat/` subdirectories. Without `XKB_CONFIG_ROOT`, only built-in + JSON keymaps are available. +4. **Keymap switch not taking effect** — Write the keymap name to `/scheme/keymap/active` or open `/scheme/keymap/set/`. Verify the name exists in `cat /scheme/keymap/list`. The compositor/terminal must re-read the active keymap after a switch — the daemon only updates its internal state. +5. **`sample_scancode_30` shows 'a' when expecting another character** — Verify the keymap is actually active (`cat /scheme/keymap/active` returns `name=`). If `active` shows the correct keymap, check the keymap's own scancode table (`cat /scheme/keymap/keymap/`). diff --git a/local/docs/operator-runbooks/redbear-polkit.md b/local/docs/operator-runbooks/redbear-polkit.md new file mode 100644 index 0000000000..d4ee3bceaa --- /dev/null +++ b/local/docs/operator-runbooks/redbear-polkit.md @@ -0,0 +1,48 @@ +# redbear-polkit — Operator Runbook + +**Daemon:** redbear-polkit +**Init service:** `/usr/lib/init.d/70_polkit.service` +**Status check:** `dbus-send --system --dest=org.freedesktop.PolicyKit1 --type=method_call --print-reply /org/freedesktop/PolicyKit1/Authority org.freedesktop.DBus.Properties.Get string:org.freedesktop.PolicyKit1.Authority string:BackendName` +**Restart:** `init-svc restart polkit` + +## Logs +- Destination: `stderr` (visible via `journalctl -u polkit`) +- Verbose authorization logging: Every `CheckAuthorization` call logs `subject_kind`, `uid`, `action_id`, and result. +- Connection retry logging: Connection failures emit `redbear-polkit: attempt N/3 failed (...)` on stderr. + +## D-Bus Registration +- **Bus:** system +- **Well-known name:** `org.freedesktop.PolicyKit1` +- **Object path:** `/org/freedesktop/PolicyKit1/Authority` +- **Connection retries:** 3 attempts at 1-second intervals. Waits up to 30 seconds for the D-Bus socket to appear. + +## Policy File +- **Default path:** `/etc/polkit-1/policy.toml` +- **Override:** `REDBEAR_POLKIT_POLICY` env var +- **Format:** One action per line: `action_id = user_spec1, user_spec2, ...` +- **User spec syntax:** + - `*` — match any user + - `1000` — match specific UID + - `@wheel` — match group membership (from `/etc/group` + `/etc/passwd`) + - `!1000` — explicit deny (prefix `!`) +- **Comments:** Lines starting with `#` are skipped +- **Default behavior:** Unknown actions are denied. UID 0 (root) is always authorized. + +## User/Group Resolution +- **`/etc/passwd`** — Default path; override with `REDBEAR_POLKIT_PASSWD` +- **`/etc/group`** — Default path; override with `REDBEAR_POLKIT_GROUP` +- Group membership check covers both primary GID (from passwd) and supplementary memberships (from group file). + +## D-Bus API +See `local/docs/dbus-interfaces/redbear-polkit.md` for the full D-Bus interface specification. + +## Signals / SIGTERM Behavior +- SIGTERM handler: Tokio-based signal handler (`tokio::signal::unix`). On receipt, shuts down via watch channel. Daemon exits cleanly with `redbear-polkit: shutdown signal received, exiting cleanly`. +- On Redox, the signal handler uses a fallback path (`tokio::signal::ctrl_c()` if `signal(SIGTERM)` fails). + +## Common Issues +1. **`timed out waiting for D-Bus socket`** — D-Bus system bus daemon not running. Start `dbus-daemon --system` first. Check `DBUS_STARTER_ADDRESS`, `DBUS_SYSTEM_BUS_ADDRESS`, or default `/run/dbus/system_bus_socket`. +2. **Policy file not found** — Default path `/etc/polkit-1/policy.toml`. Create it or override via `REDBEAR_POLKIT_POLICY`. Without a policy file, all non-root actions are denied by default. +3. **Group membership check fails for user** — Verify the user exists in `/etc/passwd` (UID parsing requires at least 4 colon-separated fields). Verify the group exists in `/etc/group` (GID in field 2, members in field 3). Group membership covers both primary GID and supplementary memberships. +4. **Deny rule not working** — Explicit deny (`!user_spec`) must appear in the same policy line as the allow spec. Order matters: `*, !1000` denies UID 1000. `!1000, *` also denies UID 1000 (explicit deny always overrides explicit allow). +5. **Connection attempts 1-3 failing** — D-Bus socket appeared but SASL auth handshake is not ready yet. This is normal for the first 1-2 seconds after `dbus-daemon` starts. The daemon retries automatically. diff --git a/mk/prefix.mk b/mk/prefix.mk index d8378873cb..edf13e1045 100644 --- a/mk/prefix.mk +++ b/mk/prefix.mk @@ -7,7 +7,10 @@ PREFIX_INSTALL=$(PREFIX)/sysroot/ PREFIX_PATH=$(ROOT)/$(PREFIX_INSTALL)/bin BINUTILS_TARGET=recipes/dev/binutils-gdb/target/$(HOST_TARGET)/$(TARGET) LIBTOOL_TARGET=recipes/dev/libtool/target/$(HOST_TARGET) -GCC_TARGET=recipes/dev/gcc13/target/$(HOST_TARGET)/$(TARGET) +# Which GCC recipe the from-source toolchain path cooks. Override to move +# the toolchain to a new GCC (e.g. GCC_RECIPE=gcc16). +GCC_RECIPE?=gcc13 +GCC_TARGET=recipes/dev/$(GCC_RECIPE)/target/$(HOST_TARGET)/$(TARGET) LIBSTDCXX_TARGET=recipes/libs/libstdcxx-v3/target/$(TARGET)/$(HOST_TARGET) RELIBC_FREESTANDING_TARGET=recipes/core/relibc/target/$(TARGET)/$(HOST_TARGET) RELIBC_TARGET=recipes/core/relibc/target/$(TARGET) @@ -110,12 +113,14 @@ else # so ::strtold is visible when the C++ wrapper runs its using. for _cstdlib in "$(COOKBOOK_ROOT)/prefix/${TARGET}/sysroot/${GNU_TARGET}/include/c++"/*/cstdlib; do \ [ -f "$$_cstdlib" ] || continue; \ + grep -q 'Red Bear: relibc declares strtold' "$$_cstdlib" && continue; \ sed -i '/^#include_next $$/a\\n// Red Bear: relibc declares strtold via cbindgen trailer.\n// The explicit include ensures ::strtold is visible when the\n// C++ wrapper processes its using-directives below.\n#include ' "$$_cstdlib"; \ done @REDOXER_TC=$(HOME)/.redoxer/$(TARGET)/toolchain/$(GNU_TARGET); \ if [ -d "$$REDOXER_TC/include/c++" ]; then \ for _cstdlib in "$$REDOXER_TC/include/c++"/*/cstdlib; do \ [ -f "$$_cstdlib" ] || continue; \ + grep -q 'Red Bear: relibc declares strtold' "$$_cstdlib" && continue; \ sed -i '/^#include_next $$/a\\n// Red Bear: relibc declares strtold via cbindgen trailer.\n// The explicit include ensures ::strtold is visible when the\n// C++ wrapper processes its using-directives below.\n#include ' "$$_cstdlib"; \ done; \ fi @@ -137,6 +142,7 @@ else # most of the C declarations) but BEFORE the first using-directive. for _cstdlib in "$(PREFIX)/gcc-install/$(GNU_TARGET)/include/c++"/*/cstdlib; do \ [ -f "$$_cstdlib" ] || continue; \ + grep -q 'Red Bear: relibc declares strtold' "$$_cstdlib" && continue; \ sed -i '/^#include_next $$/a\\n// Red Bear: relibc declares strtold via cbindgen trailer.\n// The explicit include ensures ::strtold is visible when the\n// C++ wrapper processes its using-directives below.\n#include ' "$$_cstdlib"; \ done # Propagate fresh relibc artifacts to the redoxer toolchain at @@ -310,7 +316,7 @@ else export $(PREFIX_CONFIG) PATH="$(ROOT)/$(PREFIX)/libtool-install/bin:$(ROOT)/$(PREFIX)/binutils-install/bin:$$PATH" \ COOKBOOK_LIBTOOL_DIR=$(ROOT)/$(PREFIX)/libtool-install COOKBOOK_CROSS_TARGET=$(TARGET) COOKBOOK_CROSS_GNU_TARGET=$(GNU_TARGET) \ COOKBOOK_HOST_SYSROOT=/usr COOKBOOK_CROSS_SYSROOT=$(ROOT)/$(PREFIX)/relibc-freestanding-install/$(GNU_TARGET) && \ - $(REPO_BIN) cook host:gcc13 + $(REPO_BIN) cook host:$(GCC_RECIPE) cp -r "$(GCC_TARGET)/stage/usr/". "$@.partial" cp -r "$(GCC_TARGET)/stage.cxx/usr/". "$@.partial" cp -r "$(PREFIX)/binutils-install/". "$@.partial" @@ -351,7 +357,9 @@ else cp -r "$(PREFIX)/relibc-freestanding-install/". "$@.partial" cp -r "$(PREFIX)/libtool-install/". "$@.partial" @#TODO: how to make this not conflict with libc? - rm -f "$@.partial/lib/gcc/$(GNU_TARGET)/13.2.0/include/limits.h" + @# Version-globbed: hardcoding a GCC version here made the rm silently + @# no-op after a toolchain upgrade, leaving the conflicting limits.h. + rm -f "$@.partial/lib/gcc/$(GNU_TARGET)"/*/include/limits.h # libgcc and freestanding libstdcxx export PATH="$(ROOT)/$@.partial/bin:$$PATH" && \ $(MAKE) -C "$(ROOT)/$(GCC_TARGET)/build" all-target-libgcc all-target-libstdc++-v3 && \