Project I wrote a 450KB static PID 1 micro-supervisor in Rust to replace systemd
Hey r/rust!
Over the past few months, I've been building an open-source project called **Kurogane (黒鉄)**: https://github.com/devpryan7792/kurogane
It's an engine that compiles single-purpose desktop and kiosk workloads into read-only EROFS appliances with sub-2s cold boots.
Instead of running a general-purpose init system like systemd (with hundreds of background units, D-Bus, and mutable state drift), I wrote a minimal, single-threaded micro-supervisor in Rust (`kurogane-init`) that runs directly as PID 1:
👉 **GitHub**: https://github.com/devpryan7792/kurogane
\### What I learned building a Rust PID 1:
1. **POSIX Async-Signal Safety in `pre_exec`:**Between `fork` and `execve`, taking allocator locks or doing dynamic allocations (`format!`, `Vec`, `CString`) introduces unrecoverable allocator deadlock hazards post-fork. I refactored all child sandboxing (Landlock LSM and Seccomp-BPF) to use pre-allocated static null-terminated buffers and stack-only raw syscalls before dropping privileges (`setgroups`, `setgid`, `setuid`).
2. **Fail-Closed Privilege Invariants:**If a container or kernel restricts `setuid(1000)` mapping, ignoring the return value leaves child processes running with root EUID. I enforced strict fail-closed exit codes (122–127) via `libc::_exit` directly in `pre_exec`.
3. **Zero-Poll Event-Driven Reactor:**PID 1 does not poll in a loop. It blocks indefinitely in an `epoll(7)` reactor sleeping on `signalfd(2)`. When any child exits, `SIGCHLD` wakes `epoll`, and I drain `waitpid(-1, WNOHANG)` non-blockingly to handle POSIX signal coalescing. Idle CPU utilization is 0.00%.
4. **Bijective Wayland `SCM_RIGHTS` Descriptor Demuxing:**Wayland passes file descriptors out-of-band without length tags in the 8-byte framing header. In the decoupled proxy helper, I track schema interface states to route descriptors cleanly to `wl_keyboard.keymap` and `wl_shm.create_pool` while dynamically draining unmodeled protocol extensions to prevent queue phase-shifts.
\### Footprint & Benchmarks:
* Binary Size: \~453 KB stripped static binary
* Idle RAM: 57.6 MB (Alpine/musl) to 85.4 MB (Arch)
* Cold-boot to active terminal: \~1.8s (QEMU KVM direct kernel)
* Storage: Compressed read-only EROFS + ext4 journaled persistence on `/data`
\### Looking for Community Feedback:
* Are there safer abstractions for handling raw `signalfd` and `epoll` in Rust without relying heavily on `nix`?
* Any edge cases I might encounter with POSIX signal coalescing under heavy process churning?
Repo & Architecture Docs: https://github.com/devpryan7792/kurogane
https://redd.it/1x8gimv
@r_linux
Post #43341
41