diff --git a/.cargo/config.toml b/.cargo/config.toml
new file mode 100644
index 0000000000000000000000000000000000000000..7f7750279de39bf3c588d7f25e3a7f5358aef8ba
--- /dev/null
+++ b/.cargo/config.toml
@@ -1,0 +1,2 @@
+[target.x86_64-unknown-linux-musl]
+linker = "rust-lld"
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..76daa494e2c10b171342bd3a8eea5e1b50075514
--- /dev/null
+++ b/.gitignore
@@ -1,0 +1,2 @@
+/build/
+/target/
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000000000000000000000000000000000000..646be65f97da6249769edd265d19a6fcd3fc6e2c
--- /dev/null
+++ b/Cargo.lock
@@ -1,0 +1,16 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "cheesed"
+version = "0.1.0"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.189"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..cca7371514a4fcb16da49518ef6c8e5675fcf673
--- /dev/null
+++ b/Cargo.toml
@@ -1,0 +1,17 @@
+[package]
+name = "cheesed"
+version = "0.1.0"
+edition = "2024"
+rust-version = "1.85"
+description = "MOUSE PID 1 and service supervisor"
+license = "BSD-2-Clause"
+
+[dependencies]
+libc = "=0.2.189"
+
+[lints.rust]
+unsafe_op_in_unsafe_fn = "deny"
+
+[lints.clippy]
+all = "deny"
+pedantic = "deny"
diff --git a/PLAN.md b/PLAN.md
new file mode 100644
index 0000000000000000000000000000000000000000..25af1ae02383d89764673f763bdf87d3ec5ad66e
--- /dev/null
+++ b/PLAN.md
@@ -1,0 +1,302 @@
+# cheesed plan
+
+## Purpose
+
+`cheesed` is MOUSE's PID 1 and boot coordinator. It establishes early userspace,
+applies canonical service-enable policy from `/etc/rc.conf`, asks OpenRC to
+execute the resulting boot graph, shuts the system down cleanly, and reaps
+orphaned children.
+
+The service framework has three deliberately separate owners:
+
+- `cheesed` owns PID 1 duties, configuration translation, boot transitions, and
+  final reboot or poweroff.
+- OpenRC owns service dependencies and ordered lifecycle actions.
+- `supervise-daemon` owns the runtime state and restart policy of each supervised
+  service.
+
+OpenRC is not PID 1 and does not remain resident after applying a runlevel.
+`cheesed` is not a second implementation of OpenRC's dependency engine or
+`supervise-daemon`'s process-monitoring loop.
+
+## Non-negotiable system contract
+
+- `cheesed` is written in Rust and built as a static musl executable.
+- Every executable shipped in the MOUSE base image, including the selected
+  OpenRC tools, is statically linked against musl. Dynamic linkage is reserved
+  for a separately defined ports policy.
+- `cheesed` is the only program launched by the kernel as PID 1 in the normal
+  system.
+- `/etc/rc.conf` is the only persistent service-enable interface.
+  `enable_sshd=YES` enables `sshd` at boot; service definitions and generated
+  runlevels never record or mutate that policy.
+- `cheesed` interprets only strict `enable_${name}=YES|NO` assignments for
+  enablement. The first release accepts no OpenRC global settings or other
+  assignment namespaces in this file.
+- OpenRC runlevel membership generated from `rc.conf` is disposable runtime
+  state under `/run` and is rebuilt on every boot.
+- MOUSE does not ship `rc-update`.
+- `service` is a symlink to `rc-service`. Its start, stop, restart, reload, and
+  status actions affect current runtime state only.
+- The base system and `cheesed` are released together. Third-party ports may
+  supply OpenRC service definitions, but must use the same `rc.conf` enablement
+  contract.
+- `cheesed` has no network dependency, dynamic-linker dependency, async runtime,
+  embedded shell, or package-manager dependency.
+
+## Design shape
+
+### Process model
+
+`cheesed` treats PID 1 as a distinct execution environment: it installs signal
+handlers early, reaps every exited child, and never relies on the usual default
+signal behaviour. It remains alive after OpenRC has completed the requested
+runlevel and while `supervise-daemon` instances manage services.
+
+The initial version is synchronous and event-driven. It may use a small polling
+loop around signal delivery and child-status changes, but it must not use Tokio
+or a general task runtime. Rust's standard library plus narrowly scoped Unix
+bindings are sufficient; unsafe code is allowed only in a small, reviewed
+syscall boundary.
+
+`supervise-daemon` is authoritative for the child process it supervises.
+`cheesed` may reap unrelated or orphaned descendants, but it must not duplicate
+service restart decisions or infer supervised service state from pidfiles.
+
+### Boot stages
+
+The kernel and early userspace provide a usable root filesystem and invoke
+`/sbin/cheesed`. Mount topology, root discovery, and an initramfs remain outside
+the first service-framework milestone.
+
+After its own early setup, `cheesed` runs these stages:
+
+1. **Bootstrap:** establish a safe environment, open console logging, install
+   signal handling, mount a fresh `tmpfs` at `/run`, create OpenRC's runtime
+   state directory, and read `/etc/rc.conf`.
+2. **Policy translation:** validate `enable_${name}=YES|NO` entries against the
+   installed service definitions and generate fresh OpenRC runlevel membership
+   under `/run`. Reject duplicates, malformed assignments, invalid service
+   names, and enabled services which do not exist.
+3. **System boot:** run `/sbin/openrc sysinit`, `/sbin/openrc boot`, and
+   `/sbin/openrc default`, in that order. OpenRC resolves dependencies and
+   executes service actions.
+4. **Login:** after the `default` transition, verify every required service
+   through `rc-service <name> status`. Enter recovery if any required service,
+   including the console login service, is not started.
+5. **Steady state:** reap orphaned children, process shutdown or reboot signals,
+   and leave individual service supervision to `supervise-daemon`.
+
+A non-zero `sysinit` or `boot` transition stops the boot path and leaves a
+diagnosable console. A non-zero `default` transition is fatal only when a
+required service is not started. Otherwise `cheesed` logs each failed optional
+service, determined by running `rc-service <name> status` for every enabled
+optional service, and proceeds to steady state. An optional service which is a
+hard dependency of a required service therefore becomes boot-critical without
+requiring `cheesed` to interpret OpenRC's dependency graph.
+
+### OpenRC integration
+
+MOUSE ships the minimum statically linked OpenRC command surface needed for
+boot and administration. The initial executable set is `openrc`, `openrc-run`,
+`rc-service`, `rc-status`, `supervise-daemon`, `start-stop-daemon`, `checkpath`,
+and `rc-sstat`, plus the `runscript` and `service` links. It also ships the
+OpenRC POSIX-shell support files required by `openrc-run`. It deliberately omits
+`rc-update`, shared OpenRC libraries, and tools not exercised by the C1 service
+definitions.
+
+The C1 build produces a manifest of every OpenRC-owned runtime file. Every ELF
+in that manifest must pass the base static-link audit, and a clean image build
+must prove that every executable or shell helper referenced by the proof
+services exists in the image.
+
+Service definitions are ordinary OpenRC service scripts. They declare
+dependencies and lifecycle actions using OpenRC's interfaces. A daemon requiring
+runtime supervision is launched through `supervise-daemon`, with its restart,
+retry, health, and shutdown policy expressed in the service definition rather
+than reimplemented in `cheesed`.
+
+OpenRC retains its upstream system runlevel path, `/etc/runlevels`.
+`/etc/runlevels` is an immutable image-owned link to
+`/run/openrc/runlevels/current`. `cheesed` creates a complete generation before
+starting OpenRC:
+
+- Base-owned templates under `/usr/lib/mouse/runlevels` provide required
+  `sysinit`, `boot`, `default`, and `shutdown` membership.
+- `enable_${name}=YES` adds the matching optional service to the generated
+  `default` runlevel. `NO` or an absent assignment leaves it out.
+- `cheesed` builds `/run/openrc/runlevels/generations/${generation}`, validates
+  every membership link, creates a relative `current.new` symlink to that
+  generation, and renames `current.new` over `current` only after the tree is
+  complete. A recovery retry creates a new generation rather than modifying the
+  active one.
+- No tool edits the generated tree after boot, and the whole tree disappears
+  when `/run` is recreated.
+
+Required membership is therefore persistent only as a versioned base template;
+the effective runlevel tree consumed by OpenRC is always disposable runtime
+state.
+
+### Configuration
+
+`/etc/rc.conf` is a small, strict assignment file, not general shell input. The
+first-release grammar is deliberately complete:
+
+- Empty lines and lines whose first non-whitespace character is `#` are
+  accepted.
+- Every other line must be exactly `enable_${name}=YES` or
+  `enable_${name}=NO`, with no surrounding whitespace, quotes, escapes, inline
+  comments, expansion, or command syntax.
+- A service name must match `[a-z][a-z0-9_]*`. MOUSE service definitions and
+  ports-provided service definitions must use the same restricted name.
+- Each service may appear at most once. A duplicate is an error even if both
+  values agree.
+- The name must resolve to exactly one installed OpenRC service definition.
+  An assignment for a required base service is an error because required
+  membership is not administrator-selectable.
+- Missing assignments mean `NO` for optional services.
+- Any other key is an error. The first release exposes no OpenRC global settings
+  and has no `rc.conf.local` or include mechanism.
+
+This grammar is also a security boundary because `openrc-run` sources
+`/etc/rc.conf` in a POSIX shell. `cheesed` must validate the entire file before
+any OpenRC process is started, so every accepted line is already safe shell
+assignment syntax. Later global settings require an explicit grammar extension,
+an allowlisted value vocabulary, and parser tests; they must never be accepted
+as opaque text.
+
+`cheesed` logs the effective enabled-service set in lexical order. It never logs
+unrecognized input values after reporting the line-numbered parse error.
+
+## Command surface
+
+The initial console-oriented command surface is:
+
+- `cheesed`: PID 1 mode, used only by the boot process.
+- `openrc`: applies the generated boot or shutdown runlevel.
+- `service <name> start|stop|status|restart|reload`: the `rc-service` runtime
+  interface.
+
+There is no initial `cheesedctl` protocol or service-control socket. OpenRC and
+`supervise-daemon` already own lifecycle state, and adding a parallel control
+plane would make the ownership boundary ambiguous.
+
+Enabling or disabling a service is a configuration operation: edit
+`enable_${name}` in `/etc/rc.conf` and reboot, or use a later MOUSE-specific
+configuration tool which edits that file atomically. The `service` command must
+never persist enablement.
+
+### OpenRC transition protocol
+
+`cheesed` has an explicit transition state:
+`bootstrap`, `sysinit`, `boot`, `default`, `steady`, `recovery`, or `shutdown`.
+For each OpenRC transition it forks a direct child in a new process group,
+connects its output to the boot console, waits synchronously while still
+handling signals and `SIGCHLD`, and records the command's exit status.
+
+The initial time limits are:
+
+- 120 seconds for each of `sysinit`, `boot`, and `default`;
+- 30 seconds for `openrc shutdown`; and
+- five seconds after sending `SIGTERM` to an overdue OpenRC process group before
+  escalating to `SIGKILL`.
+
+These are release constants in C1 rather than user-controlled `rc.conf`
+settings. A timeout is reported with the transition name and is treated like a
+non-zero transition result.
+
+If a reboot or poweroff request arrives during boot, `cheesed` latches the first
+requested action and ignores later conflicting requests, terminates the active
+OpenRC process group using the five-second escalation rule, reaps it, and then
+enters shutdown. Shutdown always invokes `/sbin/openrc shutdown`, even after a
+partial boot, so OpenRC can stop anything it already marked as started. When
+that command exits or reaches its timeout, `cheesed` performs the requested
+kernel reboot or poweroff operation. No second boot transition starts after
+shutdown has been latched.
+
+## Failure and recovery policy
+
+- On boot-time configuration errors, print a precise console diagnostic and
+  spawn a recovery shell. `cheesed` remains PID 1, reaps the shell when it exits,
+  and follows an explicit retry, reboot, or poweroff path; PID 1 never returns
+  from `main`.
+- On OpenRC dependency or required-service failure, retain OpenRC's diagnostic
+  result and stop the affected boot path rather than continuing into a partially
+  defined system state.
+- On a supervised service crash, `supervise-daemon` applies the policy declared
+  by its OpenRC service definition. `cheesed` does not apply a competing restart
+  policy.
+- On `SIGTERM`, `SIGINT`, reboot, or poweroff requests, `cheesed` runs
+  `openrc shutdown` under the transition protocol above. OpenRC stops started
+  services in reverse dependency order before `cheesed` performs the requested
+  system action.
+- Reap unknown orphaned children and log them at a low rate; never let zombies
+  accumulate.
+
+## Milestones
+
+### C0: executable skeleton
+
+Create the Rust crate, cross/static build configuration, and a QEMU boot path
+that starts `cheesed` as PID 1 and reaches an emergency `tcsh` shell. Implement
+early console logging, `SIGCHLD` reaping, and signal-driven reboot and poweroff
+behaviour. `cheesed` must remain alive if the emergency shell exits or a final
+reboot syscall fails.
+
+### C1: rc.conf and OpenRC boot
+
+Statically build the required OpenRC tools. Implement the strict `rc.conf`
+enablement parser and ephemeral runlevel generator. Prove one required base
+service and one optional service, with the optional service joining the generated
+runlevel only when `enable_${name}=YES` is present.
+
+### C2: supervision and administration
+
+Run a non-daemonising test service through `supervise-daemon`, prove its restart
+and shutdown policy, and expose accurate runtime state through
+`service <name> status`. Confirm that no `service` action changes next-boot
+enablement and that `rc-update` is absent from the image.
+
+### C3: base integration
+
+Replace the proof services with console login and the minimal base services
+needed by MOUSE. Document the OpenRC service-definition contract for ports and
+prove that a ports-provided service can be enabled only through
+`/etc/rc.conf`.
+
+## Acceptance gates
+
+- The release build produces statically linked musl binaries for `cheesed` and
+  every shipped OpenRC executable.
+- A clean QEMU boot shows `cheesed` as PID 1, reaches a `tcsh` login, and leaves
+  no zombies after the test workload exits repeatedly.
+- An optional service starts only when its matching
+  `enable_${name}=YES` assignment is present; removing it prevents the service
+  from joining the next boot's generated runlevel.
+- Generated OpenRC runlevels live only in runtime state and are recreated from
+  `/etc/rc.conf` on every boot.
+- The image does not ship `rc-update`.
+- `service` resolves to `rc-service`, accurately reports a supervised test
+  service, and never changes persistent enablement.
+- OpenRC reports missing dependencies and dependency cycles without producing
+  an unordered partial start.
+- `supervise-daemon` applies the declared crash policy without a competing
+  restart decision from `cheesed`.
+- Reboot and poweroff stop services in reverse dependency order and respect the
+  configured timeout.
+- Unit tests cover parsing, enablement validation, and generated membership;
+  QEMU integration tests cover boot, optional enablement, supervision, runtime
+  service control, and shutdown.
+
+## Explicitly out of scope for the first release
+
+- Shipping `rc-update` or treating persistent runlevel symlinks as policy.
+- A custom `cheesed` dependency resolver, service supervisor, control socket, or
+  service-file format.
+- A systemd compatibility layer, unit-file import, or D-Bus API.
+- Parallel service startup before ordered serial boot is correct and observable.
+- Socket, timer, path, device, user-session, or container activation.
+- Cgroup accounting and resource limits beyond capabilities provided directly
+  by the selected OpenRC release.
+- Mounting root filesystems, discovering storage, or replacing the initramfs.
+- Shell-evaluated `enable_` values or a second persistent enablement database.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..ba267da1e454153aa838b6f4487c7cc90472d8e0
--- /dev/null
+++ b/README.md
@@ -1,0 +1,40 @@
+# cheesed
+
+`cheesed` is the PID 1 and service supervisor for MOUSE. The repository is
+currently implementing milestone C0 from [`PLAN.md`](PLAN.md): a static Linux
+init which logs to the console, reaps children, provides an emergency `tcsh`,
+and handles reboot and poweroff signals without ever returning from PID 1.
+
+## Development checks
+
+Unit tests and lint checks run on the development host:
+
+```sh
+cargo test --locked
+cargo clippy --locked --all-targets -- -D warnings
+cargo fmt --check
+```
+
+PID 1 mode is Linux-only. Build the static release binary with:
+
+```sh
+rustup target add x86_64-unknown-linux-musl
+scripts/build-static.sh
+```
+
+## C0 QEMU boot
+
+The initramfs deliberately takes an explicit static `tcsh`; it does not copy a
+host shell with unresolved dynamic-library dependencies.
+
+```sh
+scripts/build-initramfs.sh \
+    target/x86_64-unknown-linux-musl/release/cheesed \
+    /path/to/static/tcsh \
+    build/cheesed-initramfs.cpio.gz
+
+scripts/run-qemu.sh /path/to/bzImage build/cheesed-initramfs.cpio.gz
+```
+
+Inside the guest, `SIGINT` requests reboot and `SIGTERM` requests poweroff.
+Exiting the emergency shell causes `cheesed` to reap and restart it.
diff --git a/scripts/build-initramfs.sh b/scripts/build-initramfs.sh
new file mode 100755
index 0000000000000000000000000000000000000000..665224d1a45fe4f5455ab0540ec60312a5d7a5ce
--- /dev/null
+++ b/scripts/build-initramfs.sh
@@ -1,0 +1,36 @@
+#!/bin/sh
+set -eu
+
+if [ "$#" -ne 3 ]; then
+    printf '%s\n' "usage: $0 CHEESED_BINARY STATIC_TCSH OUTPUT" >&2
+    exit 2
+fi
+
+cheesed_binary=$1
+tcsh_binary=$2
+output=$3
+
+for binary in "$cheesed_binary" "$tcsh_binary"; do
+    if [ ! -x "$binary" ]; then
+        printf '%s\n' "not an executable file: $binary" >&2
+        exit 1
+    fi
+    if ! file "$binary" | grep -Eq 'statically linked|static-pie linked'; then
+        printf '%s\n' "initramfs input must be statically linked: $binary" >&2
+        exit 1
+    fi
+done
+
+staging=$(mktemp -d "${TMPDIR:-/tmp}/cheesed-initramfs.XXXXXX")
+trap 'rm -rf "$staging"' EXIT HUP INT TERM
+
+mkdir -p "$staging/bin" "$staging/dev" "$staging/proc" "$staging/root" "$staging/sbin" "$staging/sys"
+cp "$cheesed_binary" "$staging/sbin/cheesed"
+cp "$tcsh_binary" "$staging/bin/tcsh"
+
+(
+    cd "$staging"
+    find . -print | cpio -o -H newc 2>/dev/null | gzip -9
+) >"$output"
+
+printf '%s\n' "$output"
diff --git a/scripts/build-static.sh b/scripts/build-static.sh
new file mode 100755
index 0000000000000000000000000000000000000000..c3f82d461dca45f0473862d982a79e12b193c538
--- /dev/null
+++ b/scripts/build-static.sh
@@ -1,0 +1,25 @@
+#!/bin/sh
+set -eu
+
+script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+repo_dir=$(dirname "$script_dir")
+target=${CHEESED_TARGET:-x86_64-unknown-linux-musl}
+
+if ! rustup target list --installed | grep -qx "$target"; then
+    printf '%s\n' "missing Rust target: $target" >&2
+    printf '%s\n' "install it with: rustup target add $target" >&2
+    exit 1
+fi
+
+(
+    cd "$repo_dir"
+    cargo build --locked --release --target "$target"
+)
+binary="$repo_dir/target/$target/release/cheesed"
+
+if ! file "$binary" | grep -Eq 'statically linked|static-pie linked'; then
+    printf '%s\n' "release binary is not statically linked: $binary" >&2
+    exit 1
+fi
+
+printf '%s\n' "$binary"
diff --git a/scripts/run-qemu.sh b/scripts/run-qemu.sh
new file mode 100755
index 0000000000000000000000000000000000000000..1091dcb2fe8bdfd20b3ba8bf783f5f1d06657975
--- /dev/null
+++ b/scripts/run-qemu.sh
@@ -1,0 +1,26 @@
+#!/bin/sh
+set -eu
+
+if [ "$#" -ne 2 ]; then
+    printf '%s\n' "usage: $0 LINUX_KERNEL INITRAMFS" >&2
+    exit 2
+fi
+
+kernel=$1
+initramfs=$2
+
+for input in "$kernel" "$initramfs"; do
+    if [ ! -f "$input" ]; then
+        printf '%s\n' "file does not exist: $input" >&2
+        exit 1
+    fi
+done
+
+exec qemu-system-x86_64 \
+    -machine accel=tcg \
+    -m 256M \
+    -no-reboot \
+    -nographic \
+    -kernel "$kernel" \
+    -initrd "$initramfs" \
+    -append "console=ttyS0 init=/sbin/cheesed panic=-1"
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..a3dcd4ec10d03d405762a7960280970df96910a9
--- /dev/null
+++ b/src/lib.rs
@@ -1,0 +1,84 @@
+//! Core process model for the MOUSE init and service supervisor.
+
+use std::fmt;
+
+/// The first message emitted after PID 1 bootstrap succeeds.
+pub const STARTUP_BANNER: &str = concat!("Cheesed to meet you! v", env!("CARGO_PKG_VERSION"));
+
+/// The terminal system action requested from PID 1.
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub enum ShutdownAction {
+    Reboot,
+    Poweroff,
+}
+
+impl fmt::Display for ShutdownAction {
+    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::Reboot => formatter.write_str("reboot"),
+            Self::Poweroff => formatter.write_str("poweroff"),
+        }
+    }
+}
+
+/// Maps the two shutdown signals accepted during C0.
+#[must_use]
+pub fn shutdown_action(signal: i32) -> Option<ShutdownAction> {
+    match signal {
+        libc::SIGINT => Some(ShutdownAction::Reboot),
+        libc::SIGTERM => Some(ShutdownAction::Poweroff),
+        _ => None,
+    }
+}
+
+#[cfg(target_os = "linux")]
+mod linux;
+
+/// Runs `cheesed` in its normal PID 1 mode.
+///
+/// # Errors
+///
+/// Returns an error if invoked outside PID 1. Once PID 1 initialization starts,
+/// failures are logged and kept alive rather than returned.
+#[cfg(target_os = "linux")]
+pub fn run() -> Result<(), String> {
+    linux::run()
+}
+
+/// Rejects normal init mode on non-Linux development hosts.
+///
+/// # Errors
+///
+/// Always returns an error because PID 1 mode requires Linux.
+#[cfg(not(target_os = "linux"))]
+pub fn run() -> Result<(), String> {
+    Err("cheesed PID 1 mode is supported only on Linux".to_owned())
+}
+
+#[cfg(test)]
+mod tests {
+    use super::{STARTUP_BANNER, ShutdownAction, shutdown_action};
+
+    #[test]
+    fn startup_banner_includes_the_package_version() {
+        assert_eq!(STARTUP_BANNER, "Cheesed to meet you! v0.1.0");
+    }
+
+    #[test]
+    fn sigint_requests_reboot() {
+        assert_eq!(shutdown_action(libc::SIGINT), Some(ShutdownAction::Reboot));
+    }
+
+    #[test]
+    fn sigterm_requests_poweroff() {
+        assert_eq!(
+            shutdown_action(libc::SIGTERM),
+            Some(ShutdownAction::Poweroff)
+        );
+    }
+
+    #[test]
+    fn unrelated_signal_is_not_a_shutdown_request() {
+        assert_eq!(shutdown_action(libc::SIGCHLD), None);
+    }
+}
diff --git a/src/linux.rs b/src/linux.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d15a4d24ca987cda44d58e7eeeca835b88b9dc92
--- /dev/null
+++ b/src/linux.rs
@@ -1,0 +1,378 @@
+use crate::{STARTUP_BANNER, ShutdownAction, shutdown_action};
+use std::fs::{File, OpenOptions};
+use std::io::{self, Write};
+use std::os::unix::process::CommandExt;
+use std::process::{Command, Stdio};
+use std::sync::atomic::{AtomicBool, AtomicI32, Ordering};
+use std::thread;
+use std::time::{Duration, Instant};
+
+const CONSOLE_PATH: &str = "/dev/console";
+const EMERGENCY_SHELL: &str = "/bin/tcsh";
+const HOSTNAME_PATH: &str = "/etc/hostname";
+const POLL_INTERVAL: Duration = Duration::from_millis(50);
+const SHELL_RESTART_DELAY: Duration = Duration::from_secs(1);
+const SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
+
+static CHILD_EXITED: AtomicBool = AtomicBool::new(false);
+static SHUTDOWN_SIGNAL: AtomicI32 = AtomicI32::new(0);
+
+extern "C" fn handle_signal(signal: libc::c_int) {
+    if signal == libc::SIGCHLD {
+        CHILD_EXITED.store(true, Ordering::Relaxed);
+    } else {
+        SHUTDOWN_SIGNAL.store(signal, Ordering::Relaxed);
+    }
+}
+
+pub(crate) fn run() -> Result<(), String> {
+    // SAFETY: getpid has no preconditions and does not mutate memory.
+    if unsafe { libc::getpid() } != 1 {
+        return Err("normal mode must run as PID 1".to_owned());
+    }
+
+    run_pid1()
+}
+
+fn run_pid1() -> ! {
+    let mut console = loop {
+        match Console::open() {
+            Ok(console) => break console,
+            Err(error) => {
+                eprintln!("cheesed: cannot open {CONSOLE_PATH} for early boot logging: {error}");
+                thread::sleep(SHELL_RESTART_DELAY);
+            }
+        }
+    };
+
+    // SAFETY: cheesed is single-threaded here and passes a conventional process umask.
+    unsafe {
+        libc::umask(0o022);
+    }
+    if let Err(error) = std::env::set_current_dir("/") {
+        remain_alive_after_fatal_error(&mut console, &format!("cannot chdir to /: {error}"));
+    }
+    if let Err(error) = install_signal_handlers() {
+        remain_alive_after_fatal_error(
+            &mut console,
+            &format!("cannot install signal handlers: {error}"),
+        );
+    }
+    if let Err(error) = mount_early_filesystems() {
+        remain_alive_after_fatal_error(
+            &mut console,
+            &format!("cannot mount early filesystems: {error}"),
+        );
+    }
+    if let Err(error) = configure_hostname() {
+        remain_alive_after_fatal_error(
+            &mut console,
+            &format!("cannot configure hostname: {error}"),
+        );
+    }
+
+    console.write_line(STARTUP_BANNER);
+    console.log("C0 bootstrap complete; cheesed is PID 1");
+    let mut shell_pid = match spawn_emergency_shell(&mut console) {
+        Ok(pid) => Some(pid),
+        Err(error) => {
+            console.log(&error);
+            None
+        }
+    };
+
+    loop {
+        if CHILD_EXITED.swap(false, Ordering::Relaxed) {
+            let shell_exited = reap_children(&mut console, shell_pid);
+            if shell_exited {
+                shell_pid = None;
+            }
+        }
+
+        let signal = SHUTDOWN_SIGNAL.swap(0, Ordering::Relaxed);
+        if let Some(action) = shutdown_action(signal) {
+            perform_shutdown(&mut console, shell_pid, action);
+        }
+
+        if shell_pid.is_none() {
+            console.log("emergency shell exited; restarting it in one second");
+            thread::sleep(SHELL_RESTART_DELAY);
+            shell_pid = Some(match spawn_emergency_shell(&mut console) {
+                Ok(pid) => pid,
+                Err(error) => {
+                    console.log(&format!("cannot restart emergency shell: {error}"));
+                    continue;
+                }
+            });
+        }
+
+        thread::sleep(POLL_INTERVAL);
+    }
+}
+
+fn remain_alive_after_fatal_error(console: &mut Console, error: &str) -> ! {
+    console.log(error);
+    console.log("unrecoverable bootstrap failure; PID 1 will remain alive");
+    loop {
+        thread::sleep(Duration::from_secs(60));
+    }
+}
+
+struct Console {
+    file: File,
+}
+
+impl Console {
+    fn open() -> io::Result<Self> {
+        let file = OpenOptions::new()
+            .read(true)
+            .write(true)
+            .open(CONSOLE_PATH)?;
+        Ok(Self { file })
+    }
+
+    fn log(&mut self, message: &str) {
+        self.write_line(&format!("cheesed: {message}"));
+    }
+
+    fn write_line(&mut self, message: &str) {
+        let _ = writeln!(self.file, "{message}");
+        let _ = self.file.flush();
+    }
+
+    fn clone_file(&self) -> io::Result<File> {
+        self.file.try_clone()
+    }
+}
+
+fn install_signal_handlers() -> io::Result<()> {
+    for signal in [libc::SIGCHLD, libc::SIGINT, libc::SIGTERM] {
+        // SAFETY: zero is a valid initial representation for sigaction before its
+        // fields and mask are initialized below.
+        let mut action: libc::sigaction = unsafe { std::mem::zeroed() };
+        action.sa_sigaction = handle_signal as *const () as usize;
+        action.sa_flags = libc::SA_RESTART;
+        if signal == libc::SIGCHLD {
+            action.sa_flags |= libc::SA_NOCLDSTOP;
+        }
+
+        // SAFETY: action owns a valid sigset_t and the signal number is known.
+        if unsafe { libc::sigemptyset(&raw mut action.sa_mask) } == -1 {
+            return Err(io::Error::last_os_error());
+        }
+        // SAFETY: action remains alive for the call and the old action is not needed.
+        if unsafe { libc::sigaction(signal, &raw const action, std::ptr::null_mut()) } == -1 {
+            return Err(io::Error::last_os_error());
+        }
+    }
+    Ok(())
+}
+
+fn mount_early_filesystems() -> io::Result<()> {
+    mount_filesystem(c"devtmpfs".as_ptr(), c"/dev".as_ptr(), c"devtmpfs".as_ptr())?;
+    mount_filesystem(c"proc".as_ptr(), c"/proc".as_ptr(), c"proc".as_ptr())?;
+    mount_filesystem(c"sysfs".as_ptr(), c"/sys".as_ptr(), c"sysfs".as_ptr())
+}
+
+fn mount_filesystem(
+    source: *const libc::c_char,
+    target: *const libc::c_char,
+    filesystem_type: *const libc::c_char,
+) -> io::Result<()> {
+    // SAFETY: all pointers are valid, static, NUL-terminated C strings; no data
+    // argument is required for these pseudo-filesystems.
+    if unsafe {
+        libc::mount(
+            source,
+            target,
+            filesystem_type,
+            0,
+            std::ptr::null::<libc::c_void>(),
+        )
+    } == -1
+    {
+        let error = io::Error::last_os_error();
+        if error.raw_os_error() != Some(libc::EBUSY) {
+            return Err(error);
+        }
+    }
+    Ok(())
+}
+
+fn configure_hostname() -> io::Result<()> {
+    let hostname = std::fs::read_to_string(HOSTNAME_PATH)?;
+    let hostname = hostname.trim();
+    if hostname.is_empty() || hostname.as_bytes().contains(&0) {
+        return Err(io::Error::new(
+            io::ErrorKind::InvalidData,
+            format!("{HOSTNAME_PATH} must contain a non-empty hostname"),
+        ));
+    }
+
+    // SAFETY: hostname points to readable bytes for the supplied length, and
+    // sethostname does not require a terminating NUL.
+    if unsafe { libc::sethostname(hostname.as_ptr().cast::<libc::c_char>(), hostname.len()) } == -1
+    {
+        return Err(io::Error::last_os_error());
+    }
+    Ok(())
+}
+
+fn spawn_emergency_shell(console: &mut Console) -> Result<libc::pid_t, String> {
+    let stdin = console
+        .clone_file()
+        .map_err(|error| format!("cannot duplicate console input: {error}"))?;
+    let stdout = console
+        .clone_file()
+        .map_err(|error| format!("cannot duplicate console output: {error}"))?;
+    let stderr = console
+        .clone_file()
+        .map_err(|error| format!("cannot duplicate console error output: {error}"))?;
+
+    let mut command = Command::new(EMERGENCY_SHELL);
+    command
+        .arg("-l")
+        .env_clear()
+        .env("HOME", "/root")
+        .env("LOGNAME", "root")
+        .env("PATH", "/sbin:/bin:/usr/sbin:/usr/bin")
+        .env("SHELL", EMERGENCY_SHELL)
+        .env("TERM", "linux")
+        .env("USER", "root")
+        .stdin(Stdio::from(stdin))
+        .stdout(Stdio::from(stdout))
+        .stderr(Stdio::from(stderr));
+
+    // SAFETY: this closure runs after fork and before exec in the single-threaded
+    // child. It invokes only async-signal-safe system calls and reports failures
+    // through a preallocated io::Error.
+    unsafe {
+        command.pre_exec(|| {
+            if libc::setsid() == -1 {
+                return Err(io::Error::last_os_error());
+            }
+            if libc::ioctl(libc::STDIN_FILENO, libc::TIOCSCTTY, 0) == -1 {
+                return Err(io::Error::last_os_error());
+            }
+            Ok(())
+        });
+    }
+
+    let child = command
+        .spawn()
+        .map_err(|error| format!("cannot start {EMERGENCY_SHELL}: {error}"))?;
+
+    let pid = i32::try_from(child.id()).map_err(|_| "child PID does not fit pid_t".to_owned())?;
+    console.log(&format!("started emergency shell as PID {pid}"));
+    Ok(pid)
+}
+
+fn reap_children(console: &mut Console, shell_pid: Option<libc::pid_t>) -> bool {
+    let mut shell_exited = false;
+    loop {
+        let mut status = 0;
+        // SAFETY: status points to writable storage and WNOHANG makes this nonblocking.
+        let pid = unsafe { libc::waitpid(-1, &raw mut status, libc::WNOHANG) };
+        match pid {
+            value if value > 0 => {
+                let description = describe_wait_status(status);
+                if Some(value) == shell_pid {
+                    console.log(&format!("emergency shell PID {value} {description}"));
+                    shell_exited = true;
+                } else {
+                    console.log(&format!("reaped orphan PID {value} ({description})"));
+                }
+            }
+            0 => break,
+            _ => {
+                let error = io::Error::last_os_error();
+                if error.raw_os_error() != Some(libc::ECHILD) {
+                    console.log(&format!("waitpid failed: {error}"));
+                }
+                break;
+            }
+        }
+    }
+    shell_exited
+}
+
+fn describe_wait_status(status: libc::c_int) -> String {
+    if libc::WIFEXITED(status) {
+        format!("exited with status {}", libc::WEXITSTATUS(status))
+    } else if libc::WIFSIGNALED(status) {
+        format!("was killed by signal {}", libc::WTERMSIG(status))
+    } else {
+        format!("changed state with wait status {status}")
+    }
+}
+
+fn perform_shutdown(
+    console: &mut Console,
+    shell_pid: Option<libc::pid_t>,
+    action: ShutdownAction,
+) -> ! {
+    console.log(&format!("received {action} request"));
+    stop_shell(console, shell_pid);
+
+    // SAFETY: sync has no preconditions and is required before the terminal reboot call.
+    unsafe {
+        libc::sync();
+    }
+    let command = match action {
+        ShutdownAction::Reboot => libc::RB_AUTOBOOT,
+        ShutdownAction::Poweroff => libc::RB_POWER_OFF,
+    };
+    // SAFETY: cheesed is PID 1 and passes one of Linux's defined reboot commands.
+    if unsafe { libc::reboot(command) } == -1 {
+        console.log(&format!(
+            "{action} syscall failed: {}; PID 1 will remain alive",
+            io::Error::last_os_error()
+        ));
+    }
+
+    loop {
+        thread::sleep(Duration::from_secs(60));
+    }
+}
+
+fn stop_shell(console: &mut Console, shell_pid: Option<libc::pid_t>) {
+    let Some(pid) = shell_pid else {
+        return;
+    };
+
+    // SAFETY: pid is a direct child PID and SIGTERM is a valid signal.
+    if unsafe { libc::kill(pid, libc::SIGTERM) } == -1 {
+        let error = io::Error::last_os_error();
+        if error.raw_os_error() != Some(libc::ESRCH) {
+            console.log(&format!("cannot stop emergency shell PID {pid}: {error}"));
+        }
+        return;
+    }
+
+    let deadline = Instant::now() + SHUTDOWN_TIMEOUT;
+    while Instant::now() < deadline {
+        if wait_for_pid(pid) {
+            console.log(&format!("emergency shell PID {pid} stopped"));
+            return;
+        }
+        thread::sleep(POLL_INTERVAL);
+    }
+
+    console.log(&format!(
+        "emergency shell PID {pid} exceeded shutdown timeout; sending SIGKILL"
+    ));
+    // SAFETY: pid is the known shell PID and SIGKILL is a valid signal.
+    unsafe {
+        libc::kill(pid, libc::SIGKILL);
+    }
+    let _ = wait_for_pid(pid);
+}
+
+fn wait_for_pid(pid: libc::pid_t) -> bool {
+    let mut status = 0;
+    // SAFETY: status points to writable storage, pid is a known child, and WNOHANG
+    // makes the check nonblocking.
+    let result = unsafe { libc::waitpid(pid, &raw mut status, libc::WNOHANG) };
+    result == pid
+        || (result == -1 && io::Error::last_os_error().raw_os_error() == Some(libc::ECHILD))
+}
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d44fb3a2acb98901e98c12ea8f16f813a3c45851
--- /dev/null
+++ b/src/main.rs
@@ -1,0 +1,6 @@
+fn main() {
+    if let Err(error) = cheesed::run() {
+        eprintln!("cheesed: {error}");
+        std::process::exit(1);
+    }
+}
