tools: group scripts by what runs them

tools/windows/   .ps1   (pwsh, so usable from Linux and macOS too)
  tools/posix/     .sh
  tools/python/    .py
  tools/           .c and .pl

The .c and .pl files stay at the top level because they are not
host-specific: the build compiles or invokes them on every platform.

Call sites updated in the Makefile, ports/mk/port.mk, docs and the
project memory. The one thing that does not survive a move on its own is
a script deriving the repo root from its own location -- all nine
PowerShell tools used Split-Path $PSScriptRoot -Parent, and memory-sync.sh
used dirname/.., both of which quietly become tools/ one level deeper.
Two levels now.

Two pre-existing Windows failures surfaced while verifying, both real and
neither caused by the move:

  - schfs_fsck.c did not compile under mingw at all: --extract uses
    POSIX mkdir(path,mode), symlink() and link(), none of which mingw
    has. That took the whole tool with it, and `make schfs-check` with
    it. mkdir maps to _mkdir; symlink and link fail loudly rather than
    writing a regular file in their place, because an extracted tree
    that differs from the image while reporting success defeats the
    point of --extract.
  - the round-trip test then failed at `ln -s`, since Git Bash cannot
    create symlinks without developer mode. It skips with a message now.
    Not a fudge: mkschfs's mingw build cannot see a symlink either, so
    the test would have compared a tree with none against an image with
    none and called it a pass -- coverage reporting itself as present
    while being absent.

Verified on Windows: build clean, all seven bootcheck suites green,
make schfs-check passes.
This commit is contained in:
Nexoniarz 2026-08-09 14:38:02 +02:00
commit 754d96ebc5
26 changed files with 127 additions and 39 deletions

View file

@ -1,9 +1,9 @@
#!/bin/sh
# Move Claude Code's project memory between this repo and the local machine.
#
# tools/memory-sync.sh export memory on this machine -> .claude/memory/
# tools/memory-sync.sh import .claude/memory/ -> this machine
# tools/memory-sync.sh status show both sides, change nothing
# tools/posix/memory-sync.sh export memory on this machine -> .claude/memory/
# tools/posix/memory-sync.sh import .claude/memory/ -> this machine
# tools/posix/memory-sync.sh status show both sides, change nothing
#
# Why this exists
# ---------------
@ -36,9 +36,9 @@ usage() {
[ $# -eq 1 ] || usage
# Repo root: this script lives in tools/, so the parent of its directory.
# Repo root: this script lives in tools/posix/, so two levels up.
script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
repo=$(CDPATH= cd -- "$script_dir/.." && pwd)
repo=$(CDPATH= cd -- "$script_dir/../.." && pwd)
repo_mem="$repo/.claude/memory"
# The absolute path Claude Code itself sees. Under Git Bash `pwd` gives

View file

@ -1,7 +1,7 @@
#!/bin/sh
# Build a bootable SchOS ISO.
#
# tools/mkiso.sh [output.iso]
# tools/posix/mkiso.sh [output.iso]
#
# The disc boots through El Torito's "no emulation" mode, which is the only
# one of the three that fits how SchOS actually loads itself.

View file

@ -32,6 +32,27 @@ TREE=$3
WORK=$(mktemp -d)
trap 'rm -rf "$WORK"' EXIT
# Symlinks are load-bearing here, so a host that cannot create them cannot run
# this test at all.
#
# Windows is that host. Git Bash needs developer mode or MSYS=winsymlinks to
# make one, and even where it can, mkschfs's mingw build cannot *see* one --
# lstat degrades to stat and S_ISLNK is always false, by design and with a
# comment saying so. The round-trip would therefore be comparing a tree with no
# symlinks against an image with no symlinks and calling that a pass, which is
# worse than not running: it is coverage that reports itself as present and is
# not.
#
# Skipping with exit 0 so `make schfs-check` still means something on Windows
# -- the B-tree, object and space suites are all host-independent and do run.
if ! ln -s target "$WORK/.symlink-probe" 2>/dev/null; then
echo "SchFS round-trip: SKIPPED -- this host cannot create symlinks."
echo " The generated tree needs them, and mkschfs cannot see them here"
echo " anyway. Run this on Linux, macOS or BSD for real coverage."
exit 0
fi
rm -f "$WORK/.symlink-probe"
if [ -z "$TREE" ]; then
# Generated by a separate script so the same tree can be rebuilt by hand
# when debugging a failure, without running the whole round-trip.

View file

@ -32,6 +32,43 @@
#include <sys/stat.h>
#include <sys/types.h>
/* --extract on Windows.
*
* mingw has no POSIX mkdir(path, mode), no symlink() and no link(), because
* Windows has no equivalent that can be created without either a privilege or
* a reparse point. Everything else here -- --info, --check, --ls, --stat,
* --cat, --tree -- is pure reading and works unchanged; it was only --extract
* that would not compile, which took the whole tool with it and with it
* `make schfs-check`.
*
* Directories map cleanly: _mkdir takes no mode, and Windows has no POSIX
* permission bits to apply anyway. Symlinks and hard links do not map, so they
* fail loudly and say why. Silently writing a regular file in their place would
* produce an extracted tree that differs from the image while reporting
* success, which is worse than not extracting at all -- the entire point of
* --extract is comparing the result against what produced it.
*/
#ifdef _WIN32
#include <direct.h>
#define mkdir(path, mode) _mkdir(path)
static int symlink(const char *target, const char *path)
{
(void)target;
fprintf(stderr, "schfs_fsck: %s: cannot create a symlink on Windows\n", path);
errno = ENOSYS;
return -1;
}
static int link(const char *from, const char *to)
{
(void)from;
fprintf(stderr, "schfs_fsck: %s: cannot create a hard link on Windows\n", to);
errno = ENOSYS;
return -1;
}
#endif
#include "../kernel/fs/schfs/btree.c"
#include "../kernel/fs/schfs/space.c"
#include "../kernel/fs/schfs/vol.c"

View file

@ -76,7 +76,8 @@ function Find-Qemu {
}
$ErrorActionPreference = 'Stop'
$root = Split-Path $PSScriptRoot -Parent
# Repo root is two levels up: this script lives in tools/windows/.
$root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
$hda = Join-Path $root 'schos.img'
# The root filesystem. SchFS is the only root there is, so this is not a
# choice -- a kernel handed anything else on device 1 panics in forkret().

View file

@ -41,7 +41,8 @@ function Find-Qemu {
}
$ErrorActionPreference = 'Stop'
$root = Split-Path $PSScriptRoot -Parent
# Repo root is two levels up: this script lives in tools/windows/.
$root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
$hda = Join-Path $root 'schos.img'
# The root filesystem. SchFS is the only root there is: the kernel mounts
# device 1 in forkret() and panics if it is not a SchFS volume, so this is

View file

@ -46,7 +46,8 @@ function Find-Qemu {
}
$ErrorActionPreference = 'Stop'
$root = Split-Path $PSScriptRoot -Parent
# Repo root is two levels up: this script lives in tools/windows/.
$root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
$hda = Join-Path $root 'schos.img'
# The root filesystem. SchFS is the only root there is: the kernel mounts
# device 1 in forkret() and panics if it is not a SchFS volume, so this is

View file

@ -40,7 +40,8 @@ function Find-Qemu {
}
$ErrorActionPreference = 'Stop'
$root = Split-Path $PSScriptRoot -Parent
# Repo root is two levels up: this script lives in tools/windows/.
$root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
$hda = Join-Path $root 'schos.img'
# The root filesystem. SchFS is the only root there is: the kernel mounts
# device 1 in forkret() and panics if it is not a SchFS volume, so this is

View file

@ -22,7 +22,8 @@ param(
)
$ErrorActionPreference = 'Stop'
$root = Split-Path $PSScriptRoot -Parent
# Repo root is two levels up: this script lives in tools/windows/.
$root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
# What counts as ours. Everything else in the tree is either somebody else's
# source or generated output, and mixing either in makes the total meaningless.

View file

@ -41,7 +41,8 @@ function Find-Qemu {
}
$ErrorActionPreference = 'Stop'
$root = Split-Path $PSScriptRoot -Parent
# Repo root is two levels up: this script lives in tools/windows/.
$root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
Push-Location $root
function Fail($msg) {

View file

@ -44,7 +44,8 @@ function Find-Qemu {
}
$ErrorActionPreference = 'Stop'
$root = Split-Path $PSScriptRoot -Parent
# Repo root is two levels up: this script lives in tools/windows/.
$root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
$log = Join-Path $root 'build/splashshot.log'
$dir = Join-Path $root $OutDir

View file

@ -46,7 +46,8 @@ function Find-Qemu {
}
$ErrorActionPreference = 'Stop'
$root = Split-Path $PSScriptRoot -Parent
# Repo root is two levels up: this script lives in tools/windows/.
$root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
$hda = Join-Path $root 'schos.img'
# The root filesystem. SchFS is the only root there is: the kernel mounts
# device 1 in forkret() and panics if it is not a SchFS volume, so this is

View file

@ -39,7 +39,8 @@ function Find-Qemu {
}
$ErrorActionPreference = 'Stop'
$root = Split-Path $PSScriptRoot -Parent
# Repo root is two levels up: this script lives in tools/windows/.
$root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
$hda = Join-Path $root 'schos.img'
# The root filesystem. SchFS is the only root there is: the kernel mounts
# device 1 in forkret() and panics if it is not a SchFS volume, so this is