Skip to content
97 changes: 97 additions & 0 deletions FINDINGS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# CoreUtils Testing on Lind - Findings

## Task Completed

Successfully identified coreutils tests and ran them via lind_run.

## Approach

1. **Built WASM binaries**: `make coreutils` (already completed)
2. **Found test suite**: Located in `coreutils/tests/` directory
3. **Configured for testing**: Ran `./configure` to generate test Makefile
4. **Created wrappers**: Generated wrapper scripts in `src/` calling `lind_run binary.cwasm`
5. **Ran tests**: Executed `make check` with PATH pointing to wrappers

## Test Results

- **PASS**: 1 (rm/dangling-symlink)
- **FAIL**: 16
- **SKIP**: 6

## Errors Discovered

### Error #1: ioctl Syscall Not Supported

**Affected**: ls and terminal-aware utilities

**Symptom**:
```
thread 'main' panicked at crates/sysdefs/src/logging.rs:6:5:
LIND DEBUG PANIC: Lind unsupported ioctl request
Exit code: 101
```

**Cause**: Programs call ioctl() to query terminal properties

**Impact**: All ls tests fail immediately

### Error #2: Test Infrastructure Sandboxed

**Affected**: Test framework itself (test-lib.sh, make check)

**Symptom**:
```
mktemp.cwasm: failed to create directory ... No such file or directory
cat.cwasm: misc/help-version.log-t: No such file or directory
```

**Cause**: Our wrappers make ALL utilities run in Lind's sandbox, including:
- cat (reads/writes log files)
- rm (cleans up test dirs)
- mktemp (creates temp test dirs)
- chmod (sets test file permissions)

**Impact**: Test framework cannot function - tests fail during setup

### Error #3: Filesystem Access

Lind sandbox doesn't have access to host paths like `/home/lind/lind-wasm-apps/`

## Root Architectural Issue

Need TWO sets of utilities:
1. **Native** for test infrastructure (cat, rm, mkdir, chmod, mktemp)
2. **Lind-wrapped** for the binary being tested

Current approach sandboxes everything, breaking the test framework.

## Files in This PR

- `run_coreutils_tests_lind.sh` - Demonstration script
- `FINDINGS.md` - This analysis document
- Test wrappers (generated at runtime, not committed)

## How Tests Were Run
```bash
cd ~/lind-wasm-apps/coreutils
./configure
# Wrappers created in src/
make -C tests check VERBOSE=yes
```


## Additional Error Found During Full Test Run

### Error #4: Memory Allocation Failure in rm

**Symptom:**
```
wasm trap: wasm `unreachable` instruction executed
Caused by: error in sysmalloc -> _int_malloc -> __libc_malloc
```

**Cause:** The `rm` binary is attempting to allocate memory via `malloc()` but hitting an assertion failure in the allocator, triggering an `unreachable` instruction.

**Impact:** Many rm tests crash completely rather than just failing

**Root cause:** Likely related to Lind's memory management or heap size limits in WASM
273 changes: 273 additions & 0 deletions coreutils/run_coreutils_tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
#!/usr/bin/env bash
################################################################################
# manual_coreutils_tests.sh
#
# Manually tests a subset of coreutils binaries through lind-boot with
# hardcoded absolute paths to work around the cwd/chroot issue (#742).
#
# Tests 3+ utilities from each category:
# File Management: ls, cp, mv, rm, mkdir, rmdir, ln, touch
# Text Processing: cat, head, tail, wc, sort, uniq, cut, paste
# Permissions/Info: chmod, df, du, pwd, dd
# Text Manipulation: echo, printf, tr, expand, unexpand
################################################################################

set -uo pipefail

LIND_WASM_ROOT="${LIND_WASM_ROOT:-/home/lind/lind-wasm}"
LINDBOOT_BIN="$LIND_WASM_ROOT/build/lind-boot"
LINDFS_ROOT="$LIND_WASM_ROOT/lindfs"
WASM_DIR="$LIND_WASM_ROOT/lind-wasm-apps/build/bin/coreutils/wasm32-wasi"
LINDFS_BIN="/opt/coreutils"

# Test working directory — absolute path so sandbox can see it
TEST_DIR="tmp/lind-manual-tests-$$"

PASS=0
FAIL=0
TOTAL=0
LOG_FILE="manual_coreutils_results.log"

# ── Setup ────────────────────────────────────────────────────────────────────

setup() {
# Ensure bind mounts are in place
sudo mkdir -p "$LINDFS_ROOT/tmp" "$LINDFS_ROOT/home" "$LINDFS_ROOT/dev"
mkdir -p "$LINDFS_ROOT/$TEST_DIR"
}

cleanup() {
rm -rf "$LINDFS_ROOT/$TEST_DIR"
}

lind_run_stderr() {
cat $LINDFS_ROOT/tmp/lind_run_stderr
}

# ── Helper: run a test ───────────────────────────────────────────────────────

run_test() {
local name="$1"
local expected="$2"
local actual="$3"
((TOTAL++))

if [ "$expected" = "$actual" ]; then
echo " PASS: $name"
((PASS++))
else
echo " FAIL: $name"
echo " expected: $(echo "$expected" | head -3)"
echo " actual: $(echo "$actual" | head -3)"
local err=$(lind_run_stderr)
[ -n "$err" ] && echo " stderr: $(echo "$err" | head -3)"
((FAIL++))
fi
}

run_test_exitcode() {
local name="$1"
local expected_exit="$2"
shift 2
((TOTAL++))

"$@" >/dev/null 2>&1
local actual_exit=$?

if [ "$expected_exit" = "$actual_exit" ]; then
echo " PASS: $name"
((PASS++))
else
echo " FAIL: $name (expected exit $expected_exit, got $actual_exit)"
((FAIL++))
fi
}

run_test_contains() {
local name="$1"
local needle="$2"
local actual="$3"
((TOTAL++))

if echo "$actual" | grep -q "$needle"; then
echo " PASS: $name"
((PASS++))
else
echo " FAIL: $name"
echo " expected to contain: $needle"
echo " actual: $(echo "$actual" | head -3)"
local err=$(lind_run_stderr)
[ -n "$err" ] && echo " stderr: $(echo "$err" | head -3)"
((FAIL++))
fi
}

# ══════════════════════════════════════════════════════════════════════════════
setup
echo "=== Manual Coreutils Tests via Lind-boot ===" | tee "$LOG_FILE"
echo "Test dir: $TEST_DIR" | tee -a "$LOG_FILE"
echo "" | tee -a "$LOG_FILE"

# Redirect all remaining output to both terminal and log
exec > >(tee -a "$LOG_FILE") 2>&1

# ── FILE MANAGEMENT ──────────────────────────────────────────────────────────
cd $LINDFS_ROOT
echo "--- File Management ---"

# touch: create a file
lind_run bin/touch "$TEST_DIR/touchfile"
run_test "touch: create file" "yes" "$([ -f "$TEST_DIR/touchfile" ] && echo yes || echo no)"

# ls: list files
echo "hello" > "$TEST_DIR/lsfile1"
echo "world" > "$TEST_DIR/lsfile2"
actual=$(lind_run bin/ls "$TEST_DIR/lsfile1" "$TEST_DIR/lsfile2")
run_test_contains "ls: list files" "lsfile1" "$actual"

# mkdir: create directory
lind_run bin/mkdir "$TEST_DIR/newdir"
run_test "mkdir: create dir" "yes" "$([ -d "$TEST_DIR/newdir" ] && echo yes || echo no)"

# rmdir: remove directory
lind_run bin/mkdir "$TEST_DIR/removeme"
lind_run bin/rmdir "$TEST_DIR/removeme"
run_test "rmdir: remove dir" "no" "$([ -d "$TEST_DIR/removeme" ] && echo yes || echo no)"

# cp: copy file
echo "copytest" > "$TEST_DIR/original"
lind_run bin/cp "$TEST_DIR/original" "$TEST_DIR/copied"
run_test "cp: copy file" "copytest" "$(cat "$TEST_DIR/copied")"

# mv: move file
echo "movetest" > "$TEST_DIR/movesrc"
lind_run bin/mv "$TEST_DIR/movesrc" "$TEST_DIR/movedst"
run_test "mv: move file" "movetest" "$(cat "$TEST_DIR/movedst")"
run_test "mv: source removed" "no" "$([ -f "$TEST_DIR/movesrc" ] && echo yes || echo no)"

# rm: remove file
echo "deleteme" > "$TEST_DIR/rmfile"
lind_run bin/rm "$TEST_DIR/rmfile"
run_test "rm: remove file" "no" "$([ -f "$TEST_DIR/rmfile" ] && echo yes || echo no)"

# ln: create symlink
echo "linktest" > "$TEST_DIR/linkoriginal"
lind_run bin/ln -s "$TEST_DIR/linkoriginal" "$TEST_DIR/symlink"
run_test "ln: create symlink" "linktest" "$(cat "$TEST_DIR/symlink")"

echo ""

# ── TEXT PROCESSING ──────────────────────────────────────────────────────────
echo "--- Text Processing ---"

# cat: read file
echo "cattest" > "$TEST_DIR/catfile"
actual=$(lind_run bin/cat "$TEST_DIR/catfile")
run_test "cat: read file" "cattest" "$actual"

# head: first lines
printf "line1\nline2\nline3\nline4\nline5\n" > "$TEST_DIR/headfile"
actual=$(lind_run bin/head -n 2 "$TEST_DIR/headfile")
expected=$(printf "line1\nline2")
run_test "head: first 2 lines" "$expected" "$actual"

# tail: last lines
actual=$(lind_run bin/tail -n 2 "$TEST_DIR/headfile")
expected=$(printf "line4\nline5")
run_test "tail: last 2 lines" "$expected" "$actual"

# wc: word count
echo "one two three" > "$TEST_DIR/wcfile"
actual=$(lind_run bin/wc -w "$TEST_DIR/wcfile")
run_test_contains "wc: word count" "3" "$actual"

# sort: sort lines
printf "banana\napple\ncherry\n" > "$TEST_DIR/sortfile"
actual=$(lind_run bin/sort "$TEST_DIR/sortfile")
expected=$(printf "apple\nbanana\ncherry")
run_test "sort: alphabetical" "$expected" "$actual"

# uniq: deduplicate
printf "aaa\naaa\nbbb\nccc\nccc\n" > "$TEST_DIR/uniqfile"
actual=$(lind_run bin/uniq "$TEST_DIR/uniqfile")
expected=$(printf "aaa\nbbb\nccc")
run_test "uniq: deduplicate" "$expected" "$actual"

# cut: extract fields
printf "a:b:c\nd:e:f\n" > "$TEST_DIR/cutfile"
actual=$(lind_run bin/cut -d: -f2 "$TEST_DIR/cutfile")
expected=$(printf "b\ne")
run_test "cut: extract field 2" "$expected" "$actual"

# paste: merge lines
printf "A\nB\n" > "$TEST_DIR/paste1"
printf "1\n2\n" > "$TEST_DIR/paste2"
actual=$(lind_run bin/paste "$TEST_DIR/paste1" "$TEST_DIR/paste2")
expected=$(printf "A\t1\nB\t2")
run_test "paste: merge files" "$expected" "$actual"

echo ""

# ── PERMISSIONS & INFO ───────────────────────────────────────────────────────
echo "--- Permissions & Info ---"

# chmod: change permissions
echo "chmodtest" > "$TEST_DIR/chmodfile"
lind_run bin/chmod 755 "$TEST_DIR/chmodfile"
actual=$(stat -c %a "$TEST_DIR/chmodfile")
run_test "chmod: set 755" "755" "$actual"

# pwd: print working directory
actual=$(lind_run bin/pwd)
# pwd might return / (lindfs root) or something else, just check it runs
run_test_contains "pwd: outputs a path" "/" "$actual"

# du: disk usage
echo "dutest" > "$TEST_DIR/dufile"
actual=$(lind_run bin/du "$TEST_DIR/dufile")
run_test_contains "du: reports usage" "$TEST_DIR/dufile" "$actual"

# df: disk free
actual=$(lind_run bin/df)
run_test_contains "df: shows filesystem" "/" "$actual"

# dd: copy bytes
echo "ddtest" > "$TEST_DIR/ddinput"
lind_run bin/dd if="$TEST_DIR/ddinput" of="$TEST_DIR/ddoutput"
run_test "dd: copy file" "ddtest" "$(cat "$TEST_DIR/ddoutput")"

echo ""

# ── TEXT MANIPULATION ────────────────────────────────────────────────────────
echo "--- Text Manipulation ---"

# echo: print text
actual=$(lind_run bin/echo "hello world")
run_test "echo: print text" "hello world" "$actual"

# printf: formatted output
actual=$(lind_run bin/printf "%s-%s\n" "foo" "bar")
run_test "printf: format string" "foo-bar" "$actual"

# tr: translate characters
actual=$(echo "hello" | lind_run bin/tr 'a-z' 'A-Z')
run_test "tr: lowercase to upper" "HELLO" "$actual"

# expand: tabs to spaces
printf "a\tb\n" > "$TEST_DIR/expandfile"
actual=$(lind_run bin/expand "$TEST_DIR/expandfile")
run_test_contains "expand: tab to spaces" "a" "$actual"

# unexpand: spaces to tabs
printf "a b\n" > "$TEST_DIR/unexpandfile"
actual=$(lind_run bin/unexpand -a "$TEST_DIR/unexpandfile")
run_test_contains "unexpand: spaces to tab" "a" "$actual"

echo ""

# ── SUMMARY ──────────────────────────────────────────────────────────────────
echo "================================"
echo "=== Results ==="
echo "PASS: $PASS | FAIL: $FAIL | TOTAL: $TOTAL"
echo "Log saved to: $LOG_FILE"
echo "================================"
Loading