RustForge

foundry

Foundry OS: the operating system built on the Rustbelt kernel

authorGrok Bot <grokbot@localhost>2026-10-31 20:43:56 -0700
commitdf4191d29409284655df0dba5dc439e76f30e9e0
parentbd24c5787b78e179a43a84d6df20afaac5fcd9ec
treebrowse files at this commit
make test: sbase-test.sh, 86 checks of sbase on Rustbelt

79 tools/options pass; 5 known kernel gaps run as xfail (mkfifo, mknod p,
chroot, ls -a dot entries, file times on FAT/exFAT; K14); df and id are
not in sbase 0.1. An XPASS or FAIL fails the test.
Aroot/scripts/sbase-test.sh+152 -0
Mroot/scripts/selftest.sh+2 -0
Mscripts/expect-v2.txt+14 -0

3 files changed, 168 insertions, 0 deletions

@@ -0,0 +1,152 @@+# sbase-test.sh: checks suckless sbase (milestone M4), run by dash.+# The self-test runs it as `dash /scripts/sbase-test.sh`. sbase lives in+# /usr/lib/sbase, OFF the default PATH, so every tool is called by its full+# path ($S/sort, ...); the Foundry OS Rust tools stay the default.+#+# Each check prints one line:+#   sbase: ok NAME            it worked+#   sbase: FAIL NAME          it did not (the test fails)+#   sbase: xfail NAME (WHY)   a known gap, failing as expected; WHY names the+#                             kernel request in docs/kernel-requests.md+#   sbase: XPASS NAME (WHY)   a known gap that suddenly works: fixed? Move it+#                             to the plain checks (counts as a failure)+#   sbase: absent NAME        a tool that sbase 0.1 doesn't have at all+# The exit status is the number of failures (FAIL + XPASS).+#+# To try it on a Linux host against a host-built sbase:+#   SBASE=/path/to/sbase WORK=/tmp/sbase-work dash root/scripts/sbase-test.sh+# (there `uname`, `du` block sizes and the known gaps differ, of course).+S=${SBASE:-/usr/lib/sbase}+W=${WORK:-/sbase-work}+fails=0 passed=0 gaps=0 absent=0+check() { # check NAME COMMAND...  (passes when COMMAND succeeds)+    name=$1; shift+    if "$@"; then echo "sbase: ok $name"; passed=$((passed + 1))+    else echo "sbase: FAIL $name"; fails=$((fails + 1)); fi+}+xfail() { # xfail NAME WHY COMMAND...  (a known gap: COMMAND should fail)+    name=$1 why=$2; shift 2+    if "$@" > /dev/null 2>&1; then echo "sbase: XPASS $name ($why)"; fails=$((fails + 1))+    else echo "sbase: xfail $name ($why)"; gaps=$((gaps + 1)); fi+}+notin() { # notin NAME WHERE: a tool sbase doesn't have+    if [ -e "$S/$1" ]; then echo "sbase: FAIL $1 is in sbase now: test it"; fails=$((fails + 1))+    else echo "sbase: absent $1 (not part of sbase 0.1; $2)"; absent=$((absent + 1)); fi+}+eq() { [ "$1" = "$2" ] || { echo "  got '$1', want '$2'"; return 1; }; }+# j: join standard input's lines with single spaces (plain sh, no tools).+j() { r=; while IFS= read -r l; do r="$r${r:+ }$l"; done; printf '%s' "$r"; }+# lsl FILE: `ls -l FILE` split into words: $1 mode, $2 links, $3 owner,+# $4 group, $5 size, $6-$8 date. Result in $L (e.g. "$L" = "-rw-r--r-- 1 ...").+lsl() { L=$($S/ls -l "$1") || return 1; }++$S/rm -rf "$W" && $S/mkdir -p "$W" && cd "$W" || { echo "sbase: FAIL cannot use $W"; exit 1; }+printf '%s\n' 1 2 3 > nums                       # 6 bytes+printf 'hello\n' > hello                          # 6 bytes++# ---- text ----+check sort        eq "$(printf 'b\na\nc\nb\n' | $S/sort | j)" "a b b c"+check sort-n      eq "$(printf '10\n9\n100\n' | $S/sort -n | j)" "9 10 100"+check sort-u-r    eq "$(printf 'b\na\nc\nb\n' | $S/sort -u -r | j)" "c b a"+check sort-k      eq "$($S/sort -t: -k3 -n /etc/passwd | $S/cut -d: -f1 | j)" "root tyler"+check uniq-c      eq "$(printf 'a\na\nb\n' | $S/uniq -c | $S/sed 's/^ *//' | j)" "2 a 1 b"+check uniq-d      eq "$(printf 'a\na\nb\n' | $S/uniq -d)" "a"+check head        eq "$($S/seq 10 | $S/head -n 3 | j)" "1 2 3"+check tail        eq "$($S/seq 10 | $S/tail -n 2 | j)" "9 10"+check tail-plus   eq "$($S/seq 10 | $S/tail -n +9 | j)" "9 10"+check cut-f       eq "$($S/cut -d: -f1 /etc/passwd | j)" "root tyler"+check cut-c       eq "$(echo hello | $S/cut -c2-4)" "ell"+check tr          eq "$(echo hello | $S/tr a-z A-Z)" "HELLO"+check tr-d-s      eq "$(echo hello | $S/tr -d e)/$(echo hello | $S/tr -s l)" "hllo/helo"+check sed-s       eq "$(echo a:b:c | $S/sed 's/:/-/g')" "a-b-c"+check sed-d       eq "$($S/seq 3 | $S/sed 2d | j)" "1 3"+check sed-n-p     eq "$($S/sed -n '/^t/p' /etc/passwd | $S/cut -d: -f1)" "tyler"+check sed-y       eq "$(echo abc | $S/sed 'y/abc/xyz/')" "xyz"+check grep        eq "$($S/grep -c '^[rt]' /etc/passwd)/$($S/grep -v root /etc/passwd | $S/cut -d: -f1)" "2/tyler"+check wc          eq "$(set -- $(printf 'a b\nc d e\n' | $S/wc); printf '%s' "$*")" "2 5 10"+check od          eq "$(set -- $(printf 'AB\n' | $S/od -t c); printf '%s' "$*")" '0000000 A B \n 0000003'+check printf      eq "$($S/printf '%05d|%s|%x|%c|%5.2f' 42 hi 255 A 3.14159)" "00042|hi|ff|A| 3.14"+check expr        eq "$($S/expr 6 \* 7)/$($S/expr abc : 'a\(.\)')/$($S/expr 5 \> 3)" "42/b/1"+check seq         eq "$($S/seq 2 2 8 | j)/$($S/seq -s, 1 3)/$($S/seq -w 8 10 | j)" "2 4 6 8/1,2,3/08 09 10"+check basename    eq "$($S/basename /a/b/c.txt .txt)" "c"+check dirname     eq "$($S/dirname /a/b/c.txt)" "/a/b"+check paste-comm  eq "$($S/paste -s -d, nums)/$(printf 'a\nb\n' > c1; printf 'b\nc\n' > c2; $S/comm -12 c1 c2)" "1,2,3/b"+check rev-fold-nl eq "$(echo abc | $S/rev)/$(echo abcdef | $S/fold -w 2 | j)/$($S/nl -b a nums | $S/sed -n 1p | $S/tr -d ' \t')" "cba/ab cd ef/11"+check cat         eq "$($S/cat nums hello | j)" "1 2 3 hello"++# ---- checksums ----+check cksum       eq "$($S/cksum < hello)" "3015617425 6"+check sha256sum   eq "$($S/sha256sum hello)" "5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03  hello"+check sha256sum-c eval '$S/sha256sum hello > sums && $S/sha256sum -c sums > /dev/null'+check md5sum      eq "$($S/md5sum hello)" "b1946ac92492d2347c6235b4d2611184  hello"+check sha1sum     eq "$($S/sha1sum hello)" "f572d396fae9206628714fb2ce00f72e94f2258f  hello"++# ---- files, modes, links, times (A:, ext2) ----+check ls-l        eval 'lsl nums && set -- $L && eq "$1 $2 $3 $4 $5" "-rw-r--r-- 1 root root 6"'+check ls-l-owner  eval 'lsl /etc/passwd && set -- $L && eq "$3:$4" "root:root"'+check ls-ld       eval 'set -- $($S/ls -ld /etc) && eq "$1" drwxr-xr-x'+check chmod       eval '$S/chmod 640 nums && lsl nums && set -- $L && eq "$1" -rw-r-----'+check chmod-sym   eval '$S/chmod u+x,g-r nums && lsl nums && set -- $L && eq "$1" -rwx------ && $S/chmod 644 nums'+check ln-s        eval '$S/ln -s nums sym && eq "$($S/readlink sym)" nums && eq "$($S/cat sym | j)" "1 2 3" && lsl sym && case $L in l*) ;; *) false;; esac'+check ln-hard     eval '$S/ln nums hard && lsl nums && set -- $L && eq "$2" 2 && eq "$($S/ls -i nums | $S/cut -d" " -f1)" "$($S/ls -i hard | $S/cut -d" " -f1)"'+check touch-new   eval '$S/touch empty && [ -e empty ] && [ ! -s empty ]'+check touch-t     eval '$S/touch -t 200001020304 nums && lsl nums && set -- $L && eq "$6 $7 $8" "Jan 02 2000"'+check touch-d     eval '$S/touch -d 2001-02-03T04:05:06 hello && lsl hello && set -- $L && eq "$6 $7 $8" "Feb 03 2001"'+check cp-p        eval '$S/chmod 600 nums && $S/cp -p nums keep && lsl keep && set -- $L && eq "$1 $6 $7 $8" "-rw------- Jan 02 2000"'+check cp-plain    eval '$S/cp nums fresh && lsl fresh && set -- $L && [ "$8" != 2000 ]'+check cp-R-mv-rm  eval '$S/mkdir -p d/e && $S/cp nums d/e/ && $S/cp -R d d2 && $S/mv d2 d3 && [ -f d3/e/nums ] && $S/rm -r d d3 && [ ! -e d3 ]'+check rmdir       eval '$S/mkdir -p r/s && ! $S/rmdir r 2>/dev/null && $S/rmdir r/s r && [ ! -e r ]'+check dd          eval '$S/dd if=/dev/zero of=zeros bs=512 count=6 2> dd.err && eq "$($S/wc -c < zeros)" 3072 && $S/grep -q "6+0 records in" dd.err'+check dd-skip     eq "$($S/dd if=/etc/passwd bs=1 skip=5 count=4 2>/dev/null)" "x:0:"+check du          eval 'set -- $($S/du -k zeros) && eq "$1" 3'+check find        eval '$S/mkdir -p tree/a/b && $S/touch tree/x.txt tree/a/y.txt && eq "$($S/find tree -name "*.txt" | $S/sort | j)" "tree/a/y.txt tree/x.txt"'+check find-type   eq "$($S/find tree -type d | $S/sort | j)" "tree tree/a tree/a/b"+check find-newer  eval '$S/touch -t 200001010000 tree/x.txt && eq "$($S/find tree -name "*.txt" -newer tree/x.txt)" tree/a/y.txt'+check xargs       eq "$(printf 'a b\nc\n' | $S/xargs $S/echo)" "a b c"+check xargs-n     eq "$(printf 'a b c\n' | $S/xargs -n 1 $S/echo | $S/wc -l)" "3"+check tee         eval 'echo hi | $S/tee t1 > t2 && echo ho | $S/tee -a t1 > /dev/null && eq "$($S/cat t1 | j)/$($S/cat t2)" "hi ho/hi"'+check test        eval '$S/test -d / && $S/test -f /etc/passwd && ! $S/test -e /nope && $S/test 3 -lt 5 && $S/test -L sym && $S/test -s nums && ! $S/test -s empty && $S/test abc = abc'+check tar         eval '$S/tar -cf t.tar tree && $S/rm -r tree && $S/tar -xf t.tar && [ -f tree/a/y.txt ] && eq "$($S/tar -tf t.tar | $S/grep -c txt)" 2'+check cmp-split   eval '$S/cmp -s nums keep && ! $S/cmp -s nums hello && $S/split -l 1 nums part. && eq "$($S/cat part.ab)" 2'+check readlink-f  eq "$($S/readlink -f sym)" "$W/nums"+check mktemp      eval 'f=$($S/mktemp "$W/tmp.XXXXXX") && [ -f "$f" ] && d=$($S/mktemp -d "$W/dir.XXXXXX") && [ -d "$d" ]'++# ---- environment, processes, system ----+check env-i       eq "$($S/env -i FOO=bar $S/env)" "FOO=bar"+check env-u       eval '! $S/env -u PATH $S/printenv PATH > /dev/null'+check date        eq "$($S/date -u -d 0 '+%Y-%m-%d %H:%M:%S')" "1970-01-01 00:00:00"+check date-now    eval '[ "$($S/date +%Y)" -ge 2025 ]'+check yes-head    eq "$($S/yes | $S/head -n 3 | j)/$($S/yes ab | $S/head -n 2 | j)" "y y y/ab ab"+check sleep       eval 'a=$($S/date +%s); $S/sleep 1; b=$($S/date +%s); [ $((b - a)) -ge 1 ] && [ $((b - a)) -le 3 ]'+check kill-TERM   eval '$S/sleep 30 & p=$!; $S/kill $p; wait $p; eq $? 143'+check kill-9      eval '$S/sleep 30 & p=$!; $S/kill -9 $p; wait $p; eq $? 137'+check kill-l      eq "$($S/kill -l 15)" "TERM"+check nice        eq "$($S/nice -n 5 $S/echo niced)" "niced"+check renice      eval '$S/renice -n 2 -p $$ > /dev/null'+check uname       eq "$($S/uname -s)/$($S/uname -m)" "Rustbelt/x86_64"+echo "sbase: uname -sr: $($S/uname -sr)"+check whoami      eq "$($S/whoami)" "root"+check hostname    eval '[ -n "$($S/hostname)" ]'+check tail-f      eval '$S/tail -f nums > tailed & p=$!; $S/sleep 1; $S/kill $p; wait $p; eq "$? $($S/cat tailed | j)" "143 1 2 3"'+check true-false  eval '$S/true && ! $S/false'+check getconf     eq "$($S/getconf PAGESIZE)" "4096"++# ---- known gaps: the kernel (docs/kernel-requests.md K14) ----+xfail mkfifo "K14: mknodat 259 is ENOSYS" $S/mkfifo fifo+xfail mknod-p "K14: mknodat 259 is ENOSYS" $S/mknod fifo2 p+xfail chroot "K14: chroot 161 is ENOSYS" $S/chroot / $S/true+xfail ls-a-dots "K14: getdents64 has no . and .. entries" eval '$S/ls -a "$W" | $S/grep -qx "\.\."'+xfail touch-on-FAT "K14: FAT32 and exFAT keep no file times" eval '$S/touch -t 200001020304 /mnt/disk0/sbase-t && lsl /mnt/disk0/sbase-t && set -- $L && $S/rm -f /mnt/disk0/sbase-t && eq "$8" 2000'+$S/rm -f /mnt/disk0/sbase-t+# ---- tools sbase 0.1 doesn't have (its sister project ubase does) ----+notin df "ubase; busybox at M5"+notin id "ubase; busybox at M5"++cd / && $S/rm -r "$W"+check cleanup [ ! -e "$W" ]+if [ $fails = 0 ]; then+    echo "sbase-test: all $((passed + gaps + absent)) checks as expected ($passed passed, $gaps known gaps, $absent tools not in sbase)"+else+    echo "sbase-test: $fails unexpected result(s) ($passed passed, $gaps known gaps)"+fi+exit $fails
@@ -87,6 +87,8 @@ fprobe orphan dash /scripts/dash-test.sh /bin dash /scripts/v2-test.sh+# suckless sbase (M4), in /usr/lib/sbase, off PATH+dash /scripts/sbase-test.sh nosuchprogram cd Q: cd A:/tmp
@@ -86,6 +86,20 @@ dash-test: all 15 checks passed v2-test: ok share-write-read-delete v2-test: ok sh-is-dash v2-test: all 18 checks passed++# ---- sbase (M4): root/scripts/sbase-test.sh ----+sbase: ok sort+sbase: ok ls-l-owner+sbase: ok kill-TERM+sbase: uname -sr: Rustbelt @KERNEL_VERSION@+sbase: xfail mkfifo (K14: mknodat 259 is ENOSYS)+sbase: xfail mknod-p (K14: mknodat 259 is ENOSYS)+sbase: xfail chroot (K14: chroot 161 is ENOSYS)+sbase: xfail ls-a-dots (K14: getdents64 has no . and .. entries)+sbase: xfail touch-on-FAT (K14: FAT32 and exFAT keep no file times)+sbase: absent df (not part of sbase 0.1; ubase; busybox at M5)+sbase: absent id (not part of sbase 0.1; ubase; busybox at M5)+sbase-test: all 86 checks as expected (79 passed, 5 known gaps, 2 tools not in sbase) sh: nosuchprogram: command not found cd: there is no drive Q: A:/tmp $ pwd