Files
LithosAnanke/demo/start-session.sh
T
Claude 3bd81097e1 chore(license): an SPDX header on every source file that had none (LicenseRef-Starship-1.0) [skip ci]
The header scan (Captain Bob, 2026-11-10): 788 source files -- 351 with the
SL-1.0 header, 12 with the old name (docs/working/experiments, kept by
ruling), 31 under someone else's licence (tools/kconfig, Linux's, GPL-2.0:
kept), and 394 with none. Ruled: the SPDX form; capsules (.4th, .f18) and
proofs (.thy) left for a ruling of their own (mkcapsule's 64x16 block format,
content-addressed capsules).

253 files now begin
    SPDX-License-Identifier: LicenseRef-Starship-1.0
    Copyright (c) 2023-2026 Robert A. James
as a /* */ block (C, headers, assembly, linker scripts) or # lines (scripts,
Makefiles, Kconfig; below a shebang or a coding line); tools/mkcapsule.c,
which had the copyright line, gets the SPDX line only.

Not touched: docs/working/ (archive and old campaign material, as the
ruling kept the experiments); v4/system/post_cases.c (generated by
v4/tools/mkpost.py, "do not edit" -- the generator has the header).

Comments only: the kernel builds on amd64, aarch64, riscv64; make -C v4
test-32: 39 programs, 0 failures; every changed script parses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
2026-11-10 04:12:49 +00:00

66 lines
3.3 KiB
Bash
Executable File

#!/bin/bash
# SPDX-License-Identifier: LicenseRef-Starship-1.0
# Copyright (c) 2023-2026 Robert A. James
# start-session.sh -- one visitor's session: the saved demo machine, resumed at its prompt, its
# serial console on this terminal; gone when the visitor leaves or the time is up (issue #112).
# ttyd runs this once per browser connection (issue #114).
#
# demo/start-session.sh [state-dir] (default: /var/lib/starshipos-demo)
#
# Nothing a visitor does survives the session: the firmware variables are a copy, the identity
# drive's writes are discarded, the image is read-only, and the guest has no network.
set -euo pipefail
here=$(cd "$(dirname "$0")" && pwd)
. "$here/qemu-args.sh"
dir=${1:-${DEMO_STATE:-/var/lib/starshipos-demo}}
limit=${DEMO_SESSION_LIMIT:-1800} # seconds a session may last
guests=${DEMO_MAX_GUESTS:-2} # machines at once: 384 MiB each (qemu-args.sh, #116)
slots=${DEMO_SLOTS:-/run/starshipos-demo} # a lock file per machine
[ -f "$dir/state" ] || { echo "The demo is not set up yet: no saved machine in $dir." >&2; exit 1; }
# One of $guests slots, or a busy message (Captain Bob, 2026-11-07: "Limit guests and have a Busy,
# try back in a few minutes"). A slot is a lock this script holds for the session's life (flock -n:
# two visitors cannot both take the last one); it goes when the script does, however it ends. The
# machine's processes are started without the lock's descriptor ({slot}>&-), so it is this
# script's alone.
mkdir -p "$slots"
slot=
for i in $(seq 1 "$guests"); do
exec {fd}>"$slots/slot-$i.lock"
if flock -n "$fd"; then slot=$fd; break; fi
exec {fd}>&-
done
if [ -z "$slot" ]; then
printf '\r\nEvery StarshipOS machine is busy right now (%d at once on this small server).\r\n' "$guests"
printf 'Try back in a few minutes.\r\n'
sleep 20
exit 0
fi
tmp=$(mktemp -d "${TMPDIR:-/tmp}/starshipos-session.XXXXXX")
trap 'rm -rf "$tmp"' EXIT
cp "$dir/vars.fd" "$tmp/vars.fd"
demo_qemu_args "$dir" "$tmp/vars.fd"
printf '\r\nStarshipOS -- starting a throwaway machine, yours for up to %d minutes. Nothing you do is kept.\r\n' $((limit / 60))
printf 'Try: 3 4 + . : SQUARE DUP * ; 7 SQUARE .\r\n\r\n'
# QEMU is a tracked child, not exec'd, so that whatever ends the session ends the machine: ttyd
# hangs up (it signals this script only), the service stops, or the time runs out. Its console is
# a private socket, joined to this terminal by console.py only once the machine runs: keys typed
# while it loads would be lost half-way through a line.
qemu-system-x86_64 "${QEMU_ARGS[@]}" \
-chardev "socket,id=con,path=$tmp/con.sock,server=on,wait=off" -serial chardev:con \
-qmp "unix:$tmp/qmp.sock,server=on,wait=off" -monitor none \
-incoming "file:$dir/state" </dev/null {slot}>&- &
qemu=$!
( sleep "$limit"; kill "$qemu" 2>/dev/null ) {slot}>&- &
timer=$!
# The bridge is a tracked child too: bash runs a trap only once its foreground command returns,
# so a hang-up would otherwise wait on the bridge. `wait` returns to the trap at once.
python3 -I "$here/console.py" "$tmp/qmp.sock" "$tmp/con.sock" 0<&0 {slot}>&- &
bridge=$!
trap 'kill "$bridge" "$qemu" "$timer" 2>/dev/null; rm -rf "$tmp"' EXIT
trap 'exit 0' HUP TERM INT
wait "$bridge" || true
printf '\r\n\r\nThe session has ended. Reload the page for a new one.\r\n'