RustForge

foundry

Foundry OS: the operating system built on the Rustbelt kernel

authorGrok Bot <grokbot@localhost>2026-10-31 19:55:48 -0700
commit12ef9f02ff29a6368263916f136b091398bd13c5
parent4dc7c2e20678083f9c2dc70d6d03982a326bf61e
treebrowse files at this commit
Contract v2 trees: root/ (A:, /etc moved from rootfs/, v2 self-test + dash v2-test.sh), share/ (C:); dash-test.sh takes the bin dir
Aroot/README.md+17 -0
Aroot/etc/README.md+10 -0
Rrootfs/etc/group → root/etc/group+0 -0
Rrootfs/etc/hosts → root/etc/hosts+0 -0
Rrootfs/etc/motd → root/etc/motd+0 -0
Rrootfs/etc/passwd → root/etc/passwd+0 -0
Rrootfs/etc/resolv.conf → root/etc/resolv.conf+0 -0
Aroot/scripts/selftest.sh+94 -0
Aroot/scripts/v2-test.sh+60 -0
Drootfs/etc/README.md+0 -11
Mrootfs/scripts/dash-test.sh+7 -5
Ashare/README.TXT+6 -0

12 files changed, 194 insertions, 16 deletions

@@ -0,0 +1,17 @@+# root/: the root file system (drive A:, mounted at /)++Under boot contract v2 (docs/boot-contract.md) this tree becomes the ext2+**root partition** of out/foundry.img. `make image` copies it into+out/staging-v2/root and adds the programs:++| path            | what                                                   |+|-----------------|--------------------------------------------------------|+| /sbin/init      | Foundry OS init (rust/init), the first program (pid 1) |+| /bin            | rbsh, dash (also /bin/sh), the Rust tools, our C programs |+| /etc            | this repo's root/etc                                    |+| /scripts        | the self-test scripts init runs headless (`make test`) |+| /usr/bin, /tmp, /root, /home/tyler, /mnt/disk0, /mnt/share | empty dirs |++The kernel creates /dev and /proc itself. The FAT32 data disk (rootfs/,+drive B:) is mounted at /mnt/disk0, the exFAT share (share/, drive C:) at+/mnt/share.
@@ -0,0 +1,10 @@+# /etc on the root file system (drive A:)++This directory is copied to `/etc` on the ext2 root partition (boot+contract v2, `make image`). The contract-v1 image (`make image-v1`) does+not have it: under v1 the kernel builds `/` itself in memory.++- `passwd`, `group`: so musl's `getpwuid(0)` works (`ls -l` owner names, `id`).+  Login shells are `/bin/rbsh`.+- `hosts`, `resolv.conf`: name lookup through musl's resolver (DNS at 10.0.2.3).+- `motd`: the banner init prints before it starts the shells.
@@ -0,0 +1,94 @@+# Foundry OS self-test, boot contract v2 (milestone M3). In a headless+# kernel build, /sbin/init runs `rbsh /scripts/selftest.sh` on the console;+# scripts/run-headless.sh (CONTRACT=v2) checks the output against+# scripts/expect-v2.txt. rbsh echoes every line with its prompt before+# running it, so an expected line must never appear literally in a command.+#+# The drives: A: is / (ext2 root), B: the FAT32 data disk (/mnt/disk0, with+# the kernel's ABI test programs in B:/bin), C: the exFAT share (/mnt/share).+ver+drives+pwd+ls A:/+ls -l A:/sbin+ls -l A:/bin+type A:/etc/motd+grep tyler A:/etc/passwd+# B:, the data disk.+cd B:+ls+type B:/readme.txt+dir bin | wc -l+cat b:notes/todo.txt | grep -i EXT | wc -l+# Files on A: (the root is writable now).+echo first line > A:/tmp/out.txt+echo second line >> /tmp/out.txt+cat < /tmp/out.txt+md /tmp/work+copy B:/notes/todo.txt /tmp/work+touch /tmp/work/empty.txt+ls -l A:/tmp/work+del /tmp/work/todo.txt /tmp/work/empty.txt /tmp/work+# C:, the share: read the README, copy a file in, list, delete.+cd C:+ls -l+type README.TXT+copy B:/notes/todo.txt C:/todo.txt+cat C:/todo.txt | grep -i ext2+md C:/made-here+echo written by Foundry OS > C:/made-here/note.txt+type C:/made-here/note.txt+ls -l C:/+del C:/todo.txt C:/made-here/note.txt C:/made-here+dir C:/+start sleep 1+wait+run evil+run overflow+start spin+start spin+sysinfo+wait+# Networking; the 108 KB download goes to the share this time.+ifconfig+ping -c 3 -i 200 10.0.2.2+fetch http://10.0.2.100/+wget -o C:/seq.txt http://10.0.2.100/big+cat C:/seq.txt | wc -l+del C:/seq.txt+host example.com+httpd -n 1 -t 20+# Virtual drivers.+ls -l /dev+random -n 8+random -d 6 5+getty -1 /dev/hvc0+tile+tile -r+# The kernel's ABI test programs (on B:, found through PATH).+forktest+cowtest+mmaptest+sigtest+start spin 1000+kill %1+wait+kill -l+threads+echoserver+ptytest+nbtest+fputest+pathtest+rawabi+# Foundry OS's own C programs and dash.+hello-musl+fprobe+orphan+dash /scripts/dash-test.sh /bin+dash /scripts/v2-test.sh+nosuchprogram+cd Q:+cd A:/tmp+pwd+exit 0
@@ -0,0 +1,60 @@+# v2-test.sh: boot contract v2 checks, run by dash (milestone M3).+# The self-test runs it as `dash /scripts/v2-test.sh`. Each check prints+# "v2-test: ok NAME" or "v2-test: FAIL NAME"; the exit status is the+# number of failures. What "contract v2" promises is in docs/boot-contract.md.+fails=0 checks=0+check() { # check NAME COMMAND...  (passes when COMMAND succeeds)+    name=$1; shift+    checks=$((checks + 1))+    if "$@"; then echo "v2-test: ok $name"+    else echo "v2-test: FAIL $name"; fails=$((fails + 1)); fi+}+eq() { [ "$1" = "$2" ] || { echo "  got '$1', want '$2'"; return 1; }; }+# roundtrip FILE: write two lines, read them back, delete, check it's gone.+roundtrip() {+    printf 'line one\nline two\n' > "$1" || return 1+    { read a; read b; } < "$1"+    [ "$a/$b" = "line one/line two" ] || { echo "  read back '$a/$b'"; return 1; }+    rm "$1" && [ ! -e "$1" ]+}++# The environment the kernel gives pid 1, passed on by init.+check env-PATH eq "$PATH" "/sbin:/bin:/usr/bin:/mnt/disk0/bin"+check env-HOME eq "$HOME" "/"+check env-TERM eq "$TERM" "linux"+# The root file system (A:, ext2): layout and writable.+layout() { [ -x /sbin/init ] && [ -x /bin/rbsh ] && [ -d /etc ] && [ -d /usr/bin ] && [ -d /home/tyler ]; }+check root-layout layout+read first < /etc/passwd   # (our Rust grep has no ^ anchors or -c, so plain sh)+check etc-passwd eq "$first" "root:x:0:0:root:/root:/bin/rbsh"+check root-writable roundtrip /v2-test-root.txt+# /bin/sh is dash; the Rust tools come first on PATH, the kernel's ABI+# test programs (on B:) last.+check sh-is-dash [ -L /bin/sh ]+check sh-runs eq "$(sh -c 'echo $((6 * 7))')" 42+check rust-tools-first eq "$(command -v ls)" /bin/ls+check fixtures-on-B eq "$(command -v forktest)" /mnt/disk0/bin/forktest+# The data disk (B:, FAT32) at /mnt/disk0.+check B-readme [ -f /mnt/disk0/readme.txt ]+check B-writable roundtrip /mnt/disk0/v2-test-b.txt+# The share (C:, exFAT) at /mnt/share: write, read back, delete; a+# directory too; and the README that `make image` put there.+read first < /mnt/share/README.TXT+check share-readme eq "$first" "This is the Foundry OS share (drive C:, /mnt/share)."+check share-write-read-delete roundtrip /mnt/share/v2-test.txt+mkdir /mnt/share/v2dir && echo inside > /mnt/share/v2dir/f.txt+check share-subdir eq "$(cat /mnt/share/v2dir/f.txt)" inside+rm /mnt/share/v2dir/f.txt /mnt/share/v2dir   # this rm also removes empty directories+check share-subdir-deleted [ ! -e /mnt/share/v2dir ]+# A file left on the share for the host to read after the run+# (make test checks it with scripts/exfat.py and fsck.exfat).+echo "written on Foundry OS by dash" > /mnt/share/from-foundry.txt+check share-keep-file [ -s /mnt/share/from-foundry.txt ]+# An orphan for init: the subshell exits at once, its `sleep` lives on and+# is adopted by init, which must reap it (the self-test's memory check+# waits for every process to be gone).+(sleep 1 &)+check left-an-orphan true+if [ $fails = 0 ]; then echo "v2-test: all $checks checks passed"+else echo "v2-test: $fails of $checks checks FAILED"; fi+exit $fails
rootfs/etc/README.md
@@ -1,11 +0,0 @@-# /etc: for the contract-v2 root file system (milestone M3)--These files are **not** copied into the contract-v1 image: under v1 the-kernel builds `/` itself (a ramfs with its own `/etc/motd`) and our disk is-only mounted at `/mnt/disk0`. Adding them to the FAT32 disk would change the-`ls` output the self-test checks. They go live when the OS disk becomes-the ext2 root (see docs/plan.md).--- `passwd`, `group`: so musl's `getpwuid(0)` works (`ls -l` owner names, `id`).-- `hosts`, `resolv.conf`: name lookup through musl's resolver (DNS at 10.0.2.3).-- `motd`: the login banner.
@@ -1,8 +1,10 @@ # dash-test.sh: POSIX shell checks for dash (Foundry OS, milestone M2).-# The self-test runs it as `dash /mnt/disk0/scripts/dash-test.sh`. Each-# check prints "dash-test: ok NAME" or "dash-test: FAIL NAME"; the exit+# The self-test runs it as `dash /mnt/disk0/scripts/dash-test.sh` (contract+# v1) or `dash /scripts/dash-test.sh /bin` (v2): the argument is the+# directory holding the programs (default /mnt/disk0/bin). Each check prints "dash-test: ok NAME" or "dash-test: FAIL NAME"; the exit # status is the number of failures. fails=0 checks=0+bindir=${1:-/mnt/disk0/bin} check() { # check NAME COMMAND...  (passes when COMMAND succeeds)     name=$1; shift     checks=$((checks + 1))@@ -21,8 +23,8 @@ out=$(f a b c); st=$? check function-and-return eq "$out/$st" "3:a b c/3" case foo.txt in *.txt) c=yes ;; *) c=no ;; esac check case-glob eq "$c" yes-n=0; for p in /mnt/disk0/bin/*; do n=$((n + 1)); done-echo "dash-test: $n programs in /mnt/disk0/bin"+n=0; for p in "$bindir"/*; do n=$((n + 1)); done+echo "dash-test: $n programs in $bindir" check pipe-to-rust-grep eq "$(printf 'apple\nbanana\n' | grep ban)" banana echo "written by dash" > /tmp/dash-test.txt read line < /tmp/dash-test.txt@@ -40,7 +42,7 @@ sleep 1 & bg=$! wait "$bg"; st=$? check background-and-wait eq "$st" 0-tests() { [ -d /tmp ] && [ -x /mnt/disk0/bin/dash ] && [ ! -e /tmp/nope ]; }+tests() { [ -d /tmp ] && [ -x "$bindir/dash" ] && [ ! -e /tmp/nope ]; } check test-builtins tests got=; trap 'got=USR1' USR1; kill -USR1 $$ check trap-signal eq "$got" USR1
@@ -0,0 +1,6 @@+This is the Foundry OS share (drive C:, /mnt/share).++It is an exFAT partition: the file system USB sticks and SD cards use, which+Windows, macOS and Linux can all read and write. Put files here to move them+between Foundry OS and another computer. Rustbelt can create, write and+delete files here (no renames and no timestamps yet).